From be543204c9c33815b2f9db2db09017d58c1e49ea Mon Sep 17 00:00:00 2001 From: Ruben Hoenle Date: Tue, 23 Sep 2025 17:12:23 +0200 Subject: [PATCH 01/28] feat(sdk): add linter and fix linter findings relates to STACKITSDK-219 --- build.gradle | 28 +++ config/pmd/pmd-ruleset.xml | 58 ++++++ .../sdk/core/KeyFlowAuthenticator.java | 60 +++--- .../stackit/sdk/core/auth/SetupAuth.java | 8 +- .../sdk/core/config/CoreConfiguration.java | 2 - .../sdk/core/exception/ApiException.java | 13 +- .../CredentialsInFileNotFoundException.java | 1 + .../PrivateKeyNotFoundException.java | 1 + .../stackit/sdk/core/utils/TestUtils.java | 3 + .../cloud/stackit/sdk/core/utils/Utils.java | 28 ++- .../sdk/core/KeyFlowAuthenticatorTest.java | 47 +++-- .../sdk/core/KeyFlowInterceptorTest.java | 4 +- .../stackit/sdk/core/auth/SetupAuthTest.java | 137 ++++++++----- .../core/config/CoreConfigurationTest.java | 41 ++-- .../stackit/sdk/core/utils/UtilsTest.java | 12 +- .../examples/AuthenticationExample.java | 98 +++++----- .../sdk/iaas/examples/IaaSExample.java | 184 ++++++++++-------- .../examples/ResourcemanagerExample.java | 25 ++- 18 files changed, 490 insertions(+), 260 deletions(-) create mode 100644 config/pmd/pmd-ruleset.xml diff --git a/build.gradle b/build.gradle index f4d6b3f..d9f4fbe 100644 --- a/build.gradle +++ b/build.gradle @@ -3,6 +3,7 @@ plugins { id 'signing' id 'idea' id 'eclipse' + id 'pmd' id 'com.diffplug.spotless' version '6.21.0' @@ -13,6 +14,7 @@ plugins { allprojects { apply plugin: 'com.diffplug.spotless' + apply plugin: 'pmd' repositories { mavenCentral() @@ -64,6 +66,32 @@ allprojects { endWithNewline() } } + + pmd { + consoleOutput = true + toolVersion = "7.12.0" + + //rulesMinimumPriority = 5 + //ruleSets = [ + // "category/java/bestpractices.xml", + // "category/java/codestyle.xml", + // "category/java/design.xml", + // "category/java/documentation.xml", + // "category/java/errorprone.xml", + // "category/java/multithreading.xml", + // "category/java/performance.xml", + // "category/java/security.xml", + + // //"category/java/errorprone.xml", + // // "category/java/bestpractices.xml" + //] + + // This tells PMD to use your custom ruleset file. + ruleSetFiles = rootProject.files("config/pmd/pmd-ruleset.xml") + + // This is important: it prevents PMD from using its default rules. + ruleSets = [] + } } def configureMavenCentralPublishing(Project project) { diff --git a/config/pmd/pmd-ruleset.xml b/config/pmd/pmd-ruleset.xml new file mode 100644 index 0000000..f31a569 --- /dev/null +++ b/config/pmd/pmd-ruleset.xml @@ -0,0 +1,58 @@ + + + + + Custom ruleset that excludes generated code from PMD analysis. + + + .*/cloud/stackit/sdk/.*/model/.* + .*/cloud/stackit/sdk/.*/api/.* + .*/cloud/stackit/sdk/.*/ApiCallback.java + .*/cloud/stackit/sdk/.*/ApiClient.java + .*/cloud/stackit/sdk/.*/ApiResponse.java + .*/cloud/stackit/sdk/.*/GzipRequestInterceptor.java + .*/cloud/stackit/sdk/.*/JSON.java + .*/cloud/stackit/sdk/.*/Pair.java + .*/cloud/stackit/sdk/.*/ProgressRequestBody.java + .*/cloud/stackit/sdk/.*/ProgressResponseBody.java + .*/cloud/stackit/sdk/.*/ServerConfiguration.java + .*/cloud/stackit/sdk/.*/ServerVariable.java + .*/cloud/stackit/sdk/.*/StringUtil.java + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/core/src/main/java/cloud/stackit/sdk/core/KeyFlowAuthenticator.java b/core/src/main/java/cloud/stackit/sdk/core/KeyFlowAuthenticator.java index d321ed3..1307300 100644 --- a/core/src/main/java/cloud/stackit/sdk/core/KeyFlowAuthenticator.java +++ b/core/src/main/java/cloud/stackit/sdk/core/KeyFlowAuthenticator.java @@ -19,14 +19,19 @@ import java.security.interfaces.RSAPrivateKey; import java.security.spec.InvalidKeySpecException; import java.util.Date; -import java.util.HashMap; import java.util.Map; import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + import okhttp3.*; import org.jetbrains.annotations.NotNull; -/* KeyFlowAuthenticator handles the Key Flow Authentication based on the Service Account Key. */ +/* + * KeyFlowAuthenticator handles the Key Flow Authentication based on the Service Account Key. + */ public class KeyFlowAuthenticator implements Authenticator { private static final String REFRESH_TOKEN = "refresh_token"; private static final String ASSERTION = "assertion"; @@ -44,6 +49,8 @@ public class KeyFlowAuthenticator implements Authenticator { private final String tokenUrl; private long tokenLeewayInSeconds = DEFAULT_TOKEN_LEEWAY; + Lock tokenRefreshLock = new ReentrantLock(); + /** * Creates the initial service account and refreshes expired access token. * @@ -140,19 +147,19 @@ public Request authenticate(Route route, @NotNull Response response) throws IOEx protected static class KeyFlowTokenResponse { @SerializedName("access_token") - private String accessToken; + private final String accessToken; @SerializedName("refresh_token") - private String refreshToken; + private final String refreshToken; @SerializedName("expires_in") private long expiresIn; @SerializedName("scope") - private String scope; + private final String scope; @SerializedName("token_type") - private String tokenType; + private final String tokenType; public KeyFlowTokenResponse( String accessToken, @@ -184,13 +191,21 @@ protected String getAccessToken() { * @throws IOException request for new access token failed * @throws ApiException response for new access token with bad status code */ - public synchronized String getAccessToken() + public String getAccessToken() throws IOException, ApiException, InvalidKeySpecException { - if (token == null) { - createAccessToken(); - } else if (token.isExpired()) { - createAccessTokenWithRefreshToken(); + try { + tokenRefreshLock.lock(); + + if (token == null) { + createAccessToken(); + } else if (token.isExpired()) { + createAccessTokenWithRefreshToken(); + } + } + finally { + tokenRefreshLock.unlock(); } + return token.getAccessToken(); } @@ -204,7 +219,6 @@ public synchronized String getAccessToken() */ protected void createAccessToken() throws InvalidKeySpecException, IOException, JsonSyntaxException, ApiException { - String grant = "urn:ietf:params:oauth:grant-type:jwt-bearer"; String assertion; try { assertion = generateSelfSignedJWT(); @@ -213,9 +227,11 @@ protected void createAccessToken() "could not find required algorithm for jwt signing. This should not happen and should be reported on https://github.com/stackitcloud/stackit-sdk-java/issues", e); } - Response response = requestToken(grant, assertion).execute(); - parseTokenResponse(response); - response.close(); + + String grant = "urn:ietf:params:oauth:grant-type:jwt-bearer"; + try (Response response = requestToken(grant, assertion).execute()) { + parseTokenResponse(response); + } } /** @@ -228,13 +244,13 @@ protected void createAccessToken() protected synchronized void createAccessTokenWithRefreshToken() throws IOException, JsonSyntaxException, ApiException { String refreshToken = token.refreshToken; - Response response = requestToken(REFRESH_TOKEN, refreshToken).execute(); - parseTokenResponse(response); - response.close(); + try (Response response = requestToken(REFRESH_TOKEN, refreshToken).execute()) { + parseTokenResponse(response); + } } private synchronized void parseTokenResponse(Response response) - throws ApiException, JsonSyntaxException, IOException { + throws ApiException, JsonSyntaxException { if (response.code() != HttpURLConnection.HTTP_OK) { String body = null; if (response.body() != null) { @@ -256,10 +272,10 @@ private synchronized void parseTokenResponse(Response response) response.body().close(); } - private Call requestToken(String grant, String assertionValue) throws IOException { + private Call requestToken(String grant, String assertionValue) { FormBody.Builder bodyBuilder = new FormBody.Builder(); bodyBuilder.addEncoded("grant_type", grant); - String assertionKey = grant.equals(REFRESH_TOKEN) ? REFRESH_TOKEN : ASSERTION; + String assertionKey = REFRESH_TOKEN.equals(grant) ? REFRESH_TOKEN : ASSERTION; bodyBuilder.addEncoded(assertionKey, assertionValue); FormBody body = bodyBuilder.build(); @@ -289,7 +305,7 @@ private String generateSelfSignedJWT() prvKey = saKey.getCredentials().getPrivateKeyParsed(); Algorithm algorithm = Algorithm.RSA512(prvKey); - Map jwtHeader = new HashMap<>(); + Map jwtHeader = new ConcurrentHashMap<>(); jwtHeader.put("kid", saKey.getCredentials().getKid()); return JWT.create() diff --git a/core/src/main/java/cloud/stackit/sdk/core/auth/SetupAuth.java b/core/src/main/java/cloud/stackit/sdk/core/auth/SetupAuth.java index b79c08d..fa3a2f5 100644 --- a/core/src/main/java/cloud/stackit/sdk/core/auth/SetupAuth.java +++ b/core/src/main/java/cloud/stackit/sdk/core/auth/SetupAuth.java @@ -18,6 +18,7 @@ import java.nio.file.Paths; import java.util.Map; import javax.swing.filechooser.FileSystemView; + import okhttp3.Interceptor; public class SetupAuth { @@ -40,9 +41,11 @@ public class SetupAuth { * let it handle the rest. Will be removed in April 2026. */ @Deprecated + public SetupAuth() { + // deprecated + } // TODO: constructor of SetupAuth should be private after deprecated constructors/methods are // removed (only static methods should remain) - public SetupAuth() {} /** * Set up the KeyFlow Authentication and can be integrated in an OkHttp client, by adding @@ -186,7 +189,7 @@ protected static void loadPrivateKey( try { String privateKey = getPrivateKey(cfg, env); saKey.getCredentials().setPrivateKey(privateKey); - } catch (Exception e) { + } catch (CredentialsInFileNotFoundException | IOException e) { throw new PrivateKeyNotFoundException("could not find private key", e); } } @@ -216,6 +219,7 @@ protected static void loadPrivateKey( * * * @param cfg + * @param env * @return found private key * @throws CredentialsInFileNotFoundException throws if no private key could be found * @throws IOException throws if the provided path can not be found or the file within the diff --git a/core/src/main/java/cloud/stackit/sdk/core/config/CoreConfiguration.java b/core/src/main/java/cloud/stackit/sdk/core/config/CoreConfiguration.java index caa5ed3..6debb6d 100644 --- a/core/src/main/java/cloud/stackit/sdk/core/config/CoreConfiguration.java +++ b/core/src/main/java/cloud/stackit/sdk/core/config/CoreConfiguration.java @@ -13,8 +13,6 @@ public class CoreConfiguration { private String tokenCustomUrl; private Long tokenExpirationLeeway; - public CoreConfiguration() {} - public Map getDefaultHeader() { return defaultHeader; } diff --git a/core/src/main/java/cloud/stackit/sdk/core/exception/ApiException.java b/core/src/main/java/cloud/stackit/sdk/core/exception/ApiException.java index d7d6210..26779f3 100644 --- a/core/src/main/java/cloud/stackit/sdk/core/exception/ApiException.java +++ b/core/src/main/java/cloud/stackit/sdk/core/exception/ApiException.java @@ -5,14 +5,16 @@ /** ApiException class. */ public class ApiException extends Exception { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 8115526329759018011L; - private int code = 0; - private Map> responseHeaders = null; - private String responseBody = null; + private int code; + private Map> responseHeaders; + private String responseBody; /** Constructor for ApiException. */ - public ApiException() {} + public ApiException() { + super(); + } /** * Constructor for ApiException. @@ -162,6 +164,7 @@ public String getResponseBody() { * * @return The exception message */ + @Override public String getMessage() { return String.format( "Message: %s%nHTTP response code: %s%nHTTP response body: %s%nHTTP response headers: %s", diff --git a/core/src/main/java/cloud/stackit/sdk/core/exception/CredentialsInFileNotFoundException.java b/core/src/main/java/cloud/stackit/sdk/core/exception/CredentialsInFileNotFoundException.java index 052fc01..7efd80f 100644 --- a/core/src/main/java/cloud/stackit/sdk/core/exception/CredentialsInFileNotFoundException.java +++ b/core/src/main/java/cloud/stackit/sdk/core/exception/CredentialsInFileNotFoundException.java @@ -1,6 +1,7 @@ package cloud.stackit.sdk.core.exception; public class CredentialsInFileNotFoundException extends RuntimeException { + private static final long serialVersionUID = -3290974267932615412L; public CredentialsInFileNotFoundException(String msg) { super(msg); diff --git a/core/src/main/java/cloud/stackit/sdk/core/exception/PrivateKeyNotFoundException.java b/core/src/main/java/cloud/stackit/sdk/core/exception/PrivateKeyNotFoundException.java index 365ea8e..e31688e 100644 --- a/core/src/main/java/cloud/stackit/sdk/core/exception/PrivateKeyNotFoundException.java +++ b/core/src/main/java/cloud/stackit/sdk/core/exception/PrivateKeyNotFoundException.java @@ -1,6 +1,7 @@ package cloud.stackit.sdk.core.exception; public class PrivateKeyNotFoundException extends RuntimeException { + private static final long serialVersionUID = -81419539524374575L; public PrivateKeyNotFoundException(String msg) { super(msg); diff --git a/core/src/main/java/cloud/stackit/sdk/core/utils/TestUtils.java b/core/src/main/java/cloud/stackit/sdk/core/utils/TestUtils.java index a027a5b..c4a648c 100644 --- a/core/src/main/java/cloud/stackit/sdk/core/utils/TestUtils.java +++ b/core/src/main/java/cloud/stackit/sdk/core/utils/TestUtils.java @@ -1,6 +1,9 @@ package cloud.stackit.sdk.core.utils; +@SuppressWarnings("PMD.TestClassWithoutTestCases") public class TestUtils { public static final String MOCK_SERVICE_ACCOUNT_KEY = "{\"id\":\"id\",\"publicKey\":\"publicKey\",\"createdAt\":\"2025-03-26T15:08:45.915+00:00\",\"keyType\":\"keyType\",\"keyOrigin\":\"keyOrigin\",\"keyAlgorithm\":\"keyAlgo\",\"active\":true,\"validUntil\":\"2025-03-26T15:08:45.915+00:00\",\"credentials\":{\"aud\":\"aud\",\"iss\":\"iss\",\"kid\":\"kid\",\"privateKey\":\"privateKey\",\"sub\":\"sub\"}}\n"; + + public static final String MOCK_SERVICE_ACCOUNT_PRIVATE_KEY = "privateKey"; } diff --git a/core/src/main/java/cloud/stackit/sdk/core/utils/Utils.java b/core/src/main/java/cloud/stackit/sdk/core/utils/Utils.java index 5a88097..63e9afe 100644 --- a/core/src/main/java/cloud/stackit/sdk/core/utils/Utils.java +++ b/core/src/main/java/cloud/stackit/sdk/core/utils/Utils.java @@ -1,7 +1,31 @@ package cloud.stackit.sdk.core.utils; public final class Utils { - public static boolean isStringSet(String input) { - return input != null && !input.trim().isEmpty(); + private Utils() {} + + /* + * Assert a string is not null and not empty + * + * @param input The string to check + * @return check result + * */ + public static boolean isStringSet(final String input) { + return input != null && !checkTrimEmpty(input); + } + + /* + * Assert a string is not empty. Helper method because String.trim().length() == 0 + * / String.trim().isEmpty() is an inefficient way to validate a blank String. + * + * @param input The string to check + * @return check result + * */ + private static boolean checkTrimEmpty(String input) { + for (int i = 0; i < input.length(); i++) { + if (!Character.isWhitespace(input.charAt(i))) { + return false; + } + } + return true; } } diff --git a/core/src/test/java/cloud/stackit/sdk/core/KeyFlowAuthenticatorTest.java b/core/src/test/java/cloud/stackit/sdk/core/KeyFlowAuthenticatorTest.java index dac8362..7f763ce 100644 --- a/core/src/test/java/cloud/stackit/sdk/core/KeyFlowAuthenticatorTest.java +++ b/core/src/test/java/cloud/stackit/sdk/core/KeyFlowAuthenticatorTest.java @@ -22,12 +22,16 @@ import okhttp3.mockwebserver.MockWebServer; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +@SuppressWarnings("PMD.TooManyMethods") class KeyFlowAuthenticatorTest { - private static MockWebServer mockWebServer; + private MockWebServer mockWebServer; private ServiceAccountKey defaultSaKey; private OkHttpClient httpClient; + + private static final String MOCK_WEBSERVER_PATH = "/token"; private static final String PRIVATE_KEY = "-----BEGIN PRIVATE KEY-----\n" + "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC0jVPq7ACbkwW6\n" @@ -58,7 +62,7 @@ class KeyFlowAuthenticatorTest { + "h/9afEtu5aUE/m+1vGBoH8z1\n" + "-----END PRIVATE KEY-----\n"; - ServiceAccountKey createDummyServiceAccount() { + private ServiceAccountKey createDummyServiceAccount() { ServiceAccountCredentials credentials = new ServiceAccountCredentials("aud", "iss", "kid", PRIVATE_KEY, "sub"); return new ServiceAccountKey( @@ -75,7 +79,7 @@ ServiceAccountKey createDummyServiceAccount() { credentials); } - KeyFlowAuthenticator.KeyFlowTokenResponse mockResponseBody(boolean expired) + private KeyFlowAuthenticator.KeyFlowTokenResponse mockResponseBody(boolean expired) throws NoSuchAlgorithmException, InvalidKeySpecException { Date issuedAt = new Date(); Date expiredAt = Date.from(new Date().toInstant().plusSeconds(60 * 10)); @@ -106,7 +110,8 @@ void tearDown() throws IOException { } @Test - void getAccessToken_response200_noException() + @DisplayName("get access token - Response 200 - No exception") + void testGetAccessTokenResponse200NoException() throws NoSuchAlgorithmException, InvalidKeySpecException, IOException, ApiException { // Setup mockServer @@ -117,7 +122,7 @@ void getAccessToken_response200_noException() mockWebServer.enqueue(mockedResponse); // Config - HttpUrl url = mockWebServer.url("/token"); + HttpUrl url = mockWebServer.url(MOCK_WEBSERVER_PATH); CoreConfiguration cfg = new CoreConfiguration().tokenCustomUrl(url.toString()); // Use mockWebServer @@ -129,7 +134,8 @@ void getAccessToken_response200_noException() } @Test - void getAccessToken_expiredToken_noException() + @DisplayName("get access token - expired token - no exception") + void testGetAccessTokenExpiredTokenNoException() throws NoSuchAlgorithmException, InvalidKeySpecException, IOException, ApiException { // Setup expiredToken and newToken KeyFlowAuthenticator.KeyFlowTokenResponse expiredKey = mockResponseBody(true); @@ -143,7 +149,7 @@ void getAccessToken_expiredToken_noException() mockWebServer.enqueue(mockedResponse); // Config - HttpUrl url = mockWebServer.url("/token"); + HttpUrl url = mockWebServer.url(MOCK_WEBSERVER_PATH); CoreConfiguration cfg = new CoreConfiguration().tokenCustomUrl(url.toString()); // Use mockWebServer @@ -155,11 +161,12 @@ void getAccessToken_expiredToken_noException() } @Test - void createAccessToken_response200WithEmptyBody_throwsException() { + @DisplayName("create access token - response 200 with empty body - throws exception") + void createAccessTokenResponse200WithEmptyBodyThrowsException() { // Setup mockServer MockResponse mockedResponse = new MockResponse().setResponseCode(200); mockWebServer.enqueue(mockedResponse); - HttpUrl url = mockWebServer.url("/token"); + HttpUrl url = mockWebServer.url(MOCK_WEBSERVER_PATH); // Config CoreConfiguration cfg = @@ -173,11 +180,12 @@ void createAccessToken_response200WithEmptyBody_throwsException() { } @Test - void createAccessToken_response400_throwsApiException() { + @DisplayName("create access token - response 400 - throws ApiException") + void createAccessTokenResponse400ThrowsApiException() { // Setup mockServer MockResponse mockedResponse = new MockResponse().setResponseCode(400); mockWebServer.enqueue(mockedResponse); - HttpUrl url = mockWebServer.url("/token"); + HttpUrl url = mockWebServer.url(MOCK_WEBSERVER_PATH); // Config CoreConfiguration cfg = @@ -191,7 +199,8 @@ void createAccessToken_response400_throwsApiException() { } @Test - void createAccessToken_response200WithValidResponse_noException() + @DisplayName("create access token - response 200 with valid response - no exception") + void createAccessTokenResponse200WithValidResponseNoException() throws NoSuchAlgorithmException, InvalidKeySpecException { // Setup mockServer KeyFlowAuthenticator.KeyFlowTokenResponse responseBody = mockResponseBody(false); @@ -201,7 +210,7 @@ void createAccessToken_response200WithValidResponse_noException() mockWebServer.enqueue(mockedResponse); // Config - HttpUrl url = mockWebServer.url("/token"); + HttpUrl url = mockWebServer.url(MOCK_WEBSERVER_PATH); CoreConfiguration cfg = new CoreConfiguration().tokenCustomUrl(url.toString()); // Use mockWebServer @@ -213,7 +222,9 @@ void createAccessToken_response200WithValidResponse_noException() } @Test - void createAccessTokenWithRefreshToken_response200WithValidResponse_noException() + @DisplayName( + "create access token with refresh token - response 200 with valid response - no exception") + void createAccessTokenWithRefreshTokenResponse200WithValidResponseNoException() throws NoSuchAlgorithmException, InvalidKeySpecException { // Setup mockServer KeyFlowAuthenticator.KeyFlowTokenResponse mockedBody = mockResponseBody(false); @@ -223,7 +234,7 @@ void createAccessTokenWithRefreshToken_response200WithValidResponse_noException( mockWebServer.enqueue(mockedResponse); // Config - HttpUrl url = mockWebServer.url("/token"); + HttpUrl url = mockWebServer.url(MOCK_WEBSERVER_PATH); CoreConfiguration cfg = new CoreConfiguration().tokenCustomUrl(url.toString()); // Use mockWebServer @@ -236,13 +247,15 @@ void createAccessTokenWithRefreshToken_response200WithValidResponse_noException( } @Test - void createAccessTokenWithRefreshToken_response200WithEmptyBody_throwsException() + @DisplayName( + "create access token with refresh token - response 200 with empty body - throws exception") + void createAccessTokenWithRefreshTokenResponse200WithEmptyBodyThrowsException() throws NoSuchAlgorithmException, InvalidKeySpecException { // Setup mockServer KeyFlowAuthenticator.KeyFlowTokenResponse mockResponse = mockResponseBody(false); MockResponse mockedResponse = new MockResponse().setResponseCode(200); mockWebServer.enqueue(mockedResponse); - HttpUrl url = mockWebServer.url("/token"); + HttpUrl url = mockWebServer.url(MOCK_WEBSERVER_PATH); // Config CoreConfiguration cfg = diff --git a/core/src/test/java/cloud/stackit/sdk/core/KeyFlowInterceptorTest.java b/core/src/test/java/cloud/stackit/sdk/core/KeyFlowInterceptorTest.java index b6f4b39..240ee40 100644 --- a/core/src/test/java/cloud/stackit/sdk/core/KeyFlowInterceptorTest.java +++ b/core/src/test/java/cloud/stackit/sdk/core/KeyFlowInterceptorTest.java @@ -13,6 +13,7 @@ import okhttp3.mockwebserver.RecordedRequest; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; @@ -47,7 +48,8 @@ void teardown() throws IOException { } @Test - void intercept_addsAuthHeader() + @DisplayName("intercept adds auth header") + void interceptAddsAuthHeader() throws IOException, InvalidKeySpecException, ApiException, InterruptedException { final String accessToken = "my-access-token"; when(authenticator.getAccessToken()).thenReturn(accessToken); diff --git a/core/src/test/java/cloud/stackit/sdk/core/auth/SetupAuthTest.java b/core/src/test/java/cloud/stackit/sdk/core/auth/SetupAuthTest.java index 7d6871a..95ac0c3 100644 --- a/core/src/test/java/cloud/stackit/sdk/core/auth/SetupAuthTest.java +++ b/core/src/test/java/cloud/stackit/sdk/core/auth/SetupAuthTest.java @@ -9,6 +9,7 @@ import cloud.stackit.sdk.core.exception.PrivateKeyNotFoundException; import cloud.stackit.sdk.core.model.ServiceAccountCredentials; import cloud.stackit.sdk.core.model.ServiceAccountKey; +import cloud.stackit.sdk.core.utils.TestUtils; import com.google.gson.Gson; import java.io.File; import java.io.IOException; @@ -18,16 +19,21 @@ import java.security.spec.InvalidKeySpecException; import java.time.temporal.ChronoUnit; import java.util.Date; -import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import javax.swing.filechooser.FileSystemView; +import okhttp3.Interceptor; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +@SuppressWarnings("PMD.TooManyMethods") @ExtendWith(MockitoExtension.class) class SetupAuthTest { + private static final String JSON_FILE_EXTENSION = ".json"; + @Mock private EnvironmentVariables envs; private final String invalidCredentialsFilePath = FileSystemView.getFileSystemView().getHomeDirectory() @@ -38,7 +44,8 @@ class SetupAuthTest { + File.separator + "file.json"; - ServiceAccountKey createDummyServiceAccount(String privateKey) { + + private ServiceAccountKey createDummyServiceAccount(String privateKey) { ServiceAccountCredentials credentials = new ServiceAccountCredentials("aud", "iss", "kid", privateKey, "sub"); return new ServiceAccountKey( @@ -55,9 +62,9 @@ ServiceAccountKey createDummyServiceAccount(String privateKey) { credentials); } - Path createJsonFile(Map content) throws IOException { + private Path createJsonFile(Map content) throws IOException { String contentJson = new Gson().toJson(content); - Path file = Files.createTempFile("credentials", ".json"); + Path file = Files.createTempFile("credentials", JSON_FILE_EXTENSION); file.toFile().deleteOnExit(); Files.write(file, contentJson.getBytes(StandardCharsets.UTF_8)); @@ -65,12 +72,32 @@ Path createJsonFile(Map content) throws IOException { } @Test - void setupKeyFlow_readServiceAccountFromPath() - throws IOException, InvalidKeySpecException, ApiException { + @DisplayName("get access token - without running init - throws exception") + void testGetAccessTokenWithoutRunningInitThrowsException() throws IOException { + SetupAuth setupAuth = new SetupAuth(); + assertThrows(RuntimeException.class, setupAuth::getAuthHandler); + } + + @Test + @DisplayName("get access token - with running init - returns interceptor") + void testGetAccessTokenWithRunningInitReturnsInterceptor() throws IOException { + ServiceAccountKey saKey = createDummyServiceAccount(TestUtils.MOCK_SERVICE_ACCOUNT_PRIVATE_KEY); + String initSaKeyJson = new Gson().toJson(saKey); + + CoreConfiguration config = new CoreConfiguration().serviceAccountKey(initSaKeyJson); + + SetupAuth setupAuth = new SetupAuth(config); + setupAuth.init(); + assertInstanceOf(Interceptor.class, setupAuth.getAuthHandler()); + } + + @Test + @DisplayName("setup key flow - read service account from path") + void setupKeyFlowReadServiceAccountFromPath() throws IOException { // Create service account key file - ServiceAccountKey initSaKey = createDummyServiceAccount("privateKey"); + ServiceAccountKey initSaKey = createDummyServiceAccount(TestUtils.MOCK_SERVICE_ACCOUNT_PRIVATE_KEY); String initSaKeyJson = new Gson().toJson(initSaKey); - Path saKeyPath = Files.createTempFile("serviceAccountKey", ".json"); + Path saKeyPath = Files.createTempFile("serviceAccountKey", JSON_FILE_EXTENSION); saKeyPath.toFile().deleteOnExit(); Files.write(saKeyPath, initSaKeyJson.getBytes(StandardCharsets.UTF_8)); @@ -84,10 +111,10 @@ void setupKeyFlow_readServiceAccountFromPath() } @Test - void setupKeyFlow_readServiceAccountFromConfig() - throws IOException, InvalidKeySpecException, ApiException { + @DisplayName("setup key flow - read service account from config") + void setupKeyFlowReadServiceAccountFromConfig() throws IOException { // Create service account key - ServiceAccountKey initSaKey = createDummyServiceAccount("privateKey"); + ServiceAccountKey initSaKey = createDummyServiceAccount(TestUtils.MOCK_SERVICE_ACCOUNT_PRIVATE_KEY); String initSaKeyJson = new Gson().toJson(initSaKey); // Create config and read setup auth with the previous created saKey @@ -98,9 +125,10 @@ void setupKeyFlow_readServiceAccountFromConfig() } @Test - void setupKeyFlow_readServiceAccountFromKeyEnv() throws IOException { + @DisplayName("setup key flow - read service account from key env") + void setupKeyFlowReadServiceAccountFromKeyEnv() throws IOException { // Create service account key - ServiceAccountKey initSaKey = createDummyServiceAccount("privateKey"); + ServiceAccountKey initSaKey = createDummyServiceAccount(TestUtils.MOCK_SERVICE_ACCOUNT_PRIVATE_KEY); String initSaKeyJson = new Gson().toJson(initSaKey); // Mock env STACKIT_SERVICE_ACCOUNT_KEY @@ -114,13 +142,14 @@ void setupKeyFlow_readServiceAccountFromKeyEnv() throws IOException { } @Test - void setupKeyFlow_readServiceAccountFromKeyPathEnv() throws IOException { + @DisplayName("setup key flow - read service account from key path env") + void setupKeyFlowReadServiceAccountFromKeyPathEnv() throws IOException { // Create service account key ServiceAccountKey initSaKey = createDummyServiceAccount("privateKey"); String keyPathContent = new Gson().toJson(initSaKey); // Create dummy keyPathFile - Path keyPathFile = Files.createTempFile("serviceAccountKey", ".json"); + Path keyPathFile = Files.createTempFile("serviceAccountKey", JSON_FILE_EXTENSION); keyPathFile.toFile().deleteOnExit(); Files.write(keyPathFile, keyPathContent.getBytes(StandardCharsets.UTF_8)); @@ -136,12 +165,14 @@ void setupKeyFlow_readServiceAccountFromKeyPathEnv() throws IOException { } @Test - void setupKeyFlow_readServiceAccountFromPathWithoutPrivateKey_throwsException() + @DisplayName( + "setup key flow - read service account from path without private key - throws exception") + void setupKeyFlowReadServiceAccountFromPathWithoutPrivateKeyThrowsException() throws IOException, InvalidKeySpecException, ApiException { // Create service account key file ServiceAccountKey initSaKey = createDummyServiceAccount(null); String initSaKeyJson = new Gson().toJson(initSaKey); - Path saKeyPath = Files.createTempFile("serviceAccountKey", ".json"); + Path saKeyPath = Files.createTempFile("serviceAccountKey", JSON_FILE_EXTENSION); saKeyPath.toFile().deleteOnExit(); Files.write(saKeyPath, initSaKeyJson.getBytes(StandardCharsets.UTF_8)); @@ -157,8 +188,9 @@ void setupKeyFlow_readServiceAccountFromPathWithoutPrivateKey_throwsException() } @Test - void setupKeyFlow_readServiceAccountFromConfigWithoutPrivateKey_throwsException() - throws IOException, InvalidKeySpecException, ApiException { + @DisplayName( + "setup key flow - read service account from config without private key - throws exception") + void setupKeyFlowReadServiceAccountFromConfigWithoutPrivateKeyThrowsException() { // Create service account key ServiceAccountKey initSaKey = createDummyServiceAccount(null); String initSaKeyJson = new Gson().toJson(initSaKey); @@ -175,8 +207,8 @@ void setupKeyFlow_readServiceAccountFromConfigWithoutPrivateKey_throwsException( } @Test - void loadPrivateKey_setPrivateKeyFromConfig() - throws IOException, InvalidKeySpecException, ApiException { + @DisplayName("load private key - set private key from config") + void loadPrivateKeySetPrivateKeyFromConfig() { final String prvKey = "prvKey"; ServiceAccountKey saKey = createDummyServiceAccount(null); @@ -188,8 +220,8 @@ void loadPrivateKey_setPrivateKeyFromConfig() } @Test - void loadPrivateKey_doesNotOverwriteExistingPrivateKey() - throws IOException, InvalidKeySpecException, ApiException { + @DisplayName("load private key - does not overwrite existing private key") + void loadPrivateKeyDoesNotOverwriteExistingPrivateKey() { final String initialPrivateKey = "prvKey"; final String cfgPrivateKey = "prvKey-updated"; @@ -203,8 +235,8 @@ void loadPrivateKey_doesNotOverwriteExistingPrivateKey() } @Test - void loadPrivateKey_setPrivateKeyPath() - throws IOException, InvalidKeySpecException, ApiException { + @DisplayName("load private key - set private key path") + void loadPrivateKeySetPrivateKeyPath() throws IOException{ Path tempPrvKeyFile = Files.createTempFile("privateKey", ".pem"); tempPrvKeyFile.toFile().deleteOnExit(); @@ -222,8 +254,8 @@ void loadPrivateKey_setPrivateKeyPath() } @Test - void loadPrivateKey_setPrivateKeyPathViaCredentialsFile() - throws IOException, InvalidKeySpecException, ApiException { + @DisplayName("load private key - set private key path via credentials file") + void loadPrivateKeySetPrivateKeyPathViaCredentialsFile() throws IOException { // Create privateKeyFile Path tempPrvKeyFile = Files.createTempFile("privateKey", ".pem"); tempPrvKeyFile.toFile().deleteOnExit(); @@ -233,10 +265,10 @@ void loadPrivateKey_setPrivateKeyPathViaCredentialsFile() Files.write(tempPrvKeyFile, privateKeyContent.getBytes(StandardCharsets.UTF_8)); // Create credentialsFile - Path tempCredentialsFile = Files.createTempFile("credentialsFile", ".json"); + Path tempCredentialsFile = Files.createTempFile("credentialsFile", JSON_FILE_EXTENSION); tempCredentialsFile.toFile().deleteOnExit(); - Map credFileContent = new HashMap<>(); + Map credFileContent = new ConcurrentHashMap<>(); credFileContent.put( EnvironmentVariables.ENV_STACKIT_PRIVATE_KEY_PATH, tempPrvKeyFile.toAbsolutePath().toString()); @@ -257,16 +289,16 @@ void loadPrivateKey_setPrivateKeyPathViaCredentialsFile() } @Test - void loadPrivateKey_setPrivateKeyViaCredentialsFile() - throws IOException, InvalidKeySpecException, ApiException { + @DisplayName("load private key - set private key via credentials file") + void loadPrivateKeySetPrivateKeyViaCredentialsFile() throws IOException { final String privateKeyContent = ""; // Create credentialsFile - Path tempCredentialsFile = Files.createTempFile("credentialsFile", ".json"); + Path tempCredentialsFile = Files.createTempFile("credentialsFile", JSON_FILE_EXTENSION); tempCredentialsFile.toFile().deleteOnExit(); // Create dummy credentialsFile - Map credFileContent = new HashMap<>(); + Map credFileContent = new ConcurrentHashMap<>(); credFileContent.put(EnvironmentVariables.ENV_STACKIT_PRIVATE_KEY, privateKeyContent); String credFileContentJson = new Gson().toJson(credFileContent); @@ -285,7 +317,8 @@ void loadPrivateKey_setPrivateKeyViaCredentialsFile() } @Test - void loadPrivateKey_setPrivateKeyViaEnv() throws IOException { + @DisplayName("load private key - set private key via env") + void loadPrivateKeySetPrivateKeyViaEnv() { final String prvKey = "prvKey"; ServiceAccountKey saKey = createDummyServiceAccount(null); when(envs.getStackitPrivateKey()).thenReturn(prvKey); @@ -298,7 +331,8 @@ void loadPrivateKey_setPrivateKeyViaEnv() throws IOException { } @Test - void loadPrivateKey_setPrivateKeyPathViaEnv() throws IOException { + @DisplayName("load private key - set private key path via env") + void loadPrivateKeySetPrivateKeyPathViaEnv() throws IOException { final String prvKey = "prvKey"; ServiceAccountKey saKey = createDummyServiceAccount(null); Path tempPrvKeyFile = Files.createTempFile("privateKey", ".pem"); @@ -316,16 +350,16 @@ void loadPrivateKey_setPrivateKeyPathViaEnv() throws IOException { } @Test - void loadPrivateKey_setPrivateKeyViaCredentialsFileInEnv() - throws IOException, InvalidKeySpecException, ApiException { + @DisplayName("load private key - set private key via credentials file in Env") + void loadPrivateKeySetPrivateKeyViaCredentialsFileInEnv() throws IOException { final String privateKeyContent = ""; // Create credentialsFile - Path tempCredentialsFile = Files.createTempFile("credentialsFile", ".json"); + Path tempCredentialsFile = Files.createTempFile("credentialsFile", JSON_FILE_EXTENSION); tempCredentialsFile.toFile().deleteOnExit(); // Create dummy credentialsFile - Map credFileContent = new HashMap<>(); + Map credFileContent = new ConcurrentHashMap<>(); credFileContent.put(EnvironmentVariables.ENV_STACKIT_PRIVATE_KEY, privateKeyContent); String credFileContentJson = new Gson().toJson(credFileContent); @@ -343,7 +377,8 @@ void loadPrivateKey_setPrivateKeyViaCredentialsFileInEnv() } @Test - void loadPrivateKey_invalidPrivateKeyPath_throwsException() + @DisplayName("load private key - invalid private key path - throws exception") + void loadPrivateKeyInvalidPrivateKeyPathThrowsException() throws IOException, InvalidKeySpecException, ApiException { String invalidPath = @@ -366,18 +401,18 @@ void loadPrivateKey_invalidPrivateKeyPath_throwsException() } @Test - void readValueFromCredentialsFile_keyAndKeyPathSet_returnsKeyValue() - throws IOException, InvalidKeySpecException, ApiException { + @DisplayName("read value from credentials file - key and key path set - returns key value") + void readValueFromCredentialsFileKeyAndKeyPathSetReturnsKeyValue() throws IOException { String keyContent = "key"; String keyPathContent = "keyPath"; // Create dummy keyPathFile - Path keyPathFile = Files.createTempFile("serviceAccountKey", ".json"); + Path keyPathFile = Files.createTempFile("serviceAccountKey", JSON_FILE_EXTENSION); keyPathFile.toFile().deleteOnExit(); Files.write(keyPathFile, keyPathContent.getBytes(StandardCharsets.UTF_8)); // Create dummy credentialsFile - Map credentialsFileContent = new HashMap<>(); + Map credentialsFileContent = new ConcurrentHashMap<>(); credentialsFileContent.put( EnvironmentVariables.ENV_STACKIT_SERVICE_ACCOUNT_KEY, keyContent); credentialsFileContent.put( @@ -395,12 +430,12 @@ void readValueFromCredentialsFile_keyAndKeyPathSet_returnsKeyValue() } @Test - void readValueFromCredentialsFile_keySet_returnsKeyValue() - throws IOException, InvalidKeySpecException, ApiException { + @DisplayName("read value from credentials file - key set - returns key value") + void readValueFromCredentialsFileKeySetReturnsKeyValue() throws IOException { String keyContent = "key"; // Create dummy credentialsFile - Map credentialsFileContent = new HashMap<>(); + Map credentialsFileContent = new ConcurrentHashMap<>(); credentialsFileContent.put( EnvironmentVariables.ENV_STACKIT_SERVICE_ACCOUNT_KEY, keyContent); Path credentialsFile = createJsonFile(credentialsFileContent); @@ -415,16 +450,16 @@ void readValueFromCredentialsFile_keySet_returnsKeyValue() } @Test - void readValueFromCredentialsFile_KeyPathSet_returnsKeyValue() - throws IOException, InvalidKeySpecException, ApiException { + @DisplayName("read value from credentials file - key path set - returns key value") + void readValueFromCredentialsFileKeyPathSetReturnsKeyValue() throws IOException { // Create dummy keyPathFile String keyPathContent = "keyPath"; - Path keyPathFile = Files.createTempFile("serviceAccountKey", ".json"); + Path keyPathFile = Files.createTempFile("serviceAccountKey", JSON_FILE_EXTENSION); keyPathFile.toFile().deleteOnExit(); Files.write(keyPathFile, keyPathContent.getBytes(StandardCharsets.UTF_8)); // Create dummy credentialsFile - Map credentialsFileContent = new HashMap<>(); + Map credentialsFileContent = new ConcurrentHashMap<>(); credentialsFileContent.put( EnvironmentVariables.ENV_STACKIT_SERVICE_ACCOUNT_KEY_PATH, keyPathFile.toAbsolutePath().toString()); diff --git a/core/src/test/java/cloud/stackit/sdk/core/config/CoreConfigurationTest.java b/core/src/test/java/cloud/stackit/sdk/core/config/CoreConfigurationTest.java index d02897a..9a495a4 100644 --- a/core/src/test/java/cloud/stackit/sdk/core/config/CoreConfigurationTest.java +++ b/core/src/test/java/cloud/stackit/sdk/core/config/CoreConfigurationTest.java @@ -2,15 +2,16 @@ import static org.junit.jupiter.api.Assertions.*; -import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import org.junit.jupiter.api.Test; +@SuppressWarnings("PMD.TooManyMethods") class CoreConfigurationTest { @Test - void getDefaultHeader() { - HashMap map = new HashMap(); + void testGetDefaultHeader() { + Map map = new ConcurrentHashMap<>(); map.put("key", "value"); CoreConfiguration cfg = new CoreConfiguration().defaultHeader(map); Map cfgHeader = cfg.getDefaultHeader(); @@ -19,7 +20,7 @@ void getDefaultHeader() { } @Test - void getServiceAccountKey() { + void testGetServiceAccountKey() { final String saKey = ""; CoreConfiguration cfg = new CoreConfiguration().serviceAccountKey(saKey); @@ -30,7 +31,7 @@ void getServiceAccountKey() { } @Test - void getServiceAccountKeyPath() { + void testGetServiceAccountKeyPath() { final String saKeyPath = ""; CoreConfiguration cfg = new CoreConfiguration().serviceAccountKeyPath(saKeyPath); @@ -41,7 +42,7 @@ void getServiceAccountKeyPath() { } @Test - void getPrivateKeyPath() { + void testGetPrivateKeyPath() { final String privateKeyPath = ""; CoreConfiguration cfg = new CoreConfiguration().privateKeyPath(privateKeyPath); @@ -52,7 +53,7 @@ void getPrivateKeyPath() { } @Test - void getPrivateKey() { + void testGetPrivateKey() { final String privateKey = ""; CoreConfiguration cfg = new CoreConfiguration().privateKey(privateKey); @@ -63,7 +64,7 @@ void getPrivateKey() { } @Test - void getCustomEndpoint() { + void testGetCustomEndpoint() { final String customEndpoint = ""; CoreConfiguration cfg = new CoreConfiguration().customEndpoint(customEndpoint); @@ -74,7 +75,7 @@ void getCustomEndpoint() { } @Test - void getCredentialsFilePath() { + void testGetCredentialsFilePath() { final String credFilePath = ""; CoreConfiguration cfg = new CoreConfiguration().credentialsFilePath(credFilePath); @@ -85,7 +86,7 @@ void getCredentialsFilePath() { } @Test - void getTokenCustomUrl() { + void testGetTokenCustomUrl() { final String tokenCustomUrl = ""; CoreConfiguration cfg = new CoreConfiguration().tokenCustomUrl(tokenCustomUrl); @@ -96,7 +97,7 @@ void getTokenCustomUrl() { } @Test - void getTokenExpirationLeeway() { + void testGetTokenExpirationLeeway() { final long tokenExpireLeeway = 100; CoreConfiguration cfg = new CoreConfiguration().tokenExpirationLeeway(tokenExpireLeeway); @@ -107,7 +108,7 @@ void getTokenExpirationLeeway() { } @Test - void getDefaultHeader_not_set() { + void testGetDefaultHeaderNotSet() { CoreConfiguration cfg = new CoreConfiguration(); Map defaultHeader = cfg.getDefaultHeader(); @@ -115,7 +116,7 @@ void getDefaultHeader_not_set() { } @Test - void getServiceAccountKey_not_set() { + void testGetServiceAccountKeyNotSet() { CoreConfiguration cfg = new CoreConfiguration(); String serviceAccountKey = cfg.getServiceAccountKey(); @@ -123,7 +124,7 @@ void getServiceAccountKey_not_set() { } @Test - void getServiceAccountKeyPath_not_set() { + void testGetServiceAccountKeyPathNotSet() { CoreConfiguration cfg = new CoreConfiguration(); String serviceAccountKeyPath = cfg.getServiceAccountKeyPath(); @@ -131,7 +132,7 @@ void getServiceAccountKeyPath_not_set() { } @Test - void getPrivateKeyPath_not_set() { + void testGetPrivateKeyPathNotSet() { CoreConfiguration cfg = new CoreConfiguration(); String privateKeyPath = cfg.getPrivateKeyPath(); @@ -139,7 +140,7 @@ void getPrivateKeyPath_not_set() { } @Test - void getPrivateKey_not_set() { + void testGetPrivateKeyNotSet() { CoreConfiguration cfg = new CoreConfiguration(); String privateKey = cfg.getPrivateKey(); @@ -147,7 +148,7 @@ void getPrivateKey_not_set() { } @Test - void getCustomEndpoint_not_set() { + void testGetCustomEndpointNotSet() { CoreConfiguration cfg = new CoreConfiguration(); String customEndpoint = cfg.getCustomEndpoint(); @@ -155,7 +156,7 @@ void getCustomEndpoint_not_set() { } @Test - void getCredentialsFilePath_not_set() { + void testGetCredentialsFilePathNotSet() { CoreConfiguration cfg = new CoreConfiguration(); String credentialsFilePath = cfg.getCredentialsFilePath(); @@ -163,7 +164,7 @@ void getCredentialsFilePath_not_set() { } @Test - void getTokenCustomUrl_not_set() { + void testGetTokenCustomUrlNotSet() { CoreConfiguration cfg = new CoreConfiguration(); String tokenCustomUrl = cfg.getTokenCustomUrl(); @@ -171,7 +172,7 @@ void getTokenCustomUrl_not_set() { } @Test - void getTokenExpirationLeeway_not_set() { + void testGetTokenExpirationLeewayNotSet() { CoreConfiguration cfg = new CoreConfiguration(); Long tokenExpirationLeeway = cfg.getTokenExpirationLeeway(); diff --git a/core/src/test/java/cloud/stackit/sdk/core/utils/UtilsTest.java b/core/src/test/java/cloud/stackit/sdk/core/utils/UtilsTest.java index 3180081..04effd9 100644 --- a/core/src/test/java/cloud/stackit/sdk/core/utils/UtilsTest.java +++ b/core/src/test/java/cloud/stackit/sdk/core/utils/UtilsTest.java @@ -7,36 +7,36 @@ class UtilsTest { @Test - void isStringSet_null_returnsFalse() { + void isStringSetNull() { assertFalse(Utils.isStringSet(null)); } @Test - void isStringSet_nullString_returnsFalse() { + void isStringSetNullString() { String nullString = null; assertFalse(Utils.isStringSet(nullString)); } @Test - void isStringSet_emptyString_returnsFalse() { + void isStringSetEmptyString() { String nullString = ""; assertFalse(Utils.isStringSet(nullString)); } @Test - void isStringSet_stringWithWhitespaces_returnsFalse() { + void isStringSetStringWithWhitespaces() { String nullString = " "; assertFalse(Utils.isStringSet(nullString)); } @Test - void isStringSet_stringWithText_returnsTrue() { + void isStringSetStringWithText() { String nullString = "text"; assertTrue(Utils.isStringSet(nullString)); } @Test - void isStringSet_stringWithTextAndWhitespaces_returnsTrue() { + void isStringSetStringWithTextAndWhitespaces() { String nullString = " text "; assertTrue(Utils.isStringSet(nullString)); } diff --git a/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java b/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java index 6dbe00f..7715447 100644 --- a/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java +++ b/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java @@ -1,22 +1,25 @@ package cloud.stackit.sdk.authentication.examples; import cloud.stackit.sdk.core.config.CoreConfiguration; +import cloud.stackit.sdk.core.exception.ApiException; import cloud.stackit.sdk.resourcemanager.api.ResourceManagerApi; import cloud.stackit.sdk.resourcemanager.model.ListOrganizationsResponse; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.util.Scanner; +import java.util.logging.Logger; -class AuthenticationExample { - public static void main(String[] args) throws IOException { - /////////////////////////////////////////////////////// - // Option 1: setting the paths to service account key (and private key) as configuration - /////////////////////////////////////////////////////// - final String SERVICE_ACCOUNT_KEY_PATH = "/path/to/sa_key.json"; - final String PRIVATE_KEY_PATH = "/path/to/private_key.pem"; - final String SERVICE_ACCOUNT_MAIL = "name-1234@sa.stackit.cloud"; +final class AuthenticationExample { + private static final Logger LOGGER = Logger.getLogger(AuthenticationExample.class.getName()); + private static final String SERVICE_ACCOUNT_KEY_PATH = "/path/to/sa_key.json"; + private static final String PRIVATE_KEY_PATH = "/path/to/private_key.pem"; + private static final String SERVICE_ACCOUNT_MAIL = "name-1234@sa.stackit.cloud"; + + @SuppressWarnings("PMD.CyclomaticComplexity") + public static void main(String[] args) { + /* OPTION 1: setting the paths to service account key (and private key) as configuration */ try { ResourceManagerApi api = new ResourceManagerApi( @@ -29,17 +32,17 @@ public static void main(String[] args) throws IOException { ListOrganizationsResponse response = api.listOrganizations(null, SERVICE_ACCOUNT_MAIL, null, null, null); - System.out.println(response); - } catch (Exception e) { + LOGGER.info(response.toString()); + } catch (ApiException | IOException e) { throw new RuntimeException(e); } - /////////////////////////////////////////////////////// - // Option 2: setting the service account key (and private key) as configuration - /////////////////////////////////////////////////////// + /* + * OPTION 2: setting the service account key (and private key) as configuration + * + * */ - // read key content from a file, in production you can also read it e.g. from STACKIT - // secrets manager, so it's only kept in-memory + /* read key content from a file, in production you can also read it e.g. from STACKIT secrets manager, so it's only kept in-memory */ String serviceAccountKeyPath = // replace it with the path to your service account key "examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/dummy_credentials/dummy-service-account-key.json"; File serviceAccountKeyFile = new File(serviceAccountKeyPath); @@ -49,7 +52,8 @@ public static void main(String[] args) throws IOException { serviceAccountKeyContent.append(myReader.nextLine()); } } catch (FileNotFoundException e) { - throw new RuntimeException(e); + System.err.println("File not found: " + serviceAccountKeyPath); + return; } String privateKeyPath = // replace it with the path to your private key @@ -61,7 +65,8 @@ public static void main(String[] args) throws IOException { privateKeyContent.append(myReader.nextLine()); } } catch (FileNotFoundException e) { - throw new RuntimeException(e); + System.err.println("File not found: " + privateKeyPath); + return; } String serviceAccountKey = serviceAccountKeyContent.toString(); @@ -79,35 +84,36 @@ public static void main(String[] args) throws IOException { ListOrganizationsResponse response = api.listOrganizations(null, SERVICE_ACCOUNT_MAIL, null, null, null); - System.out.println(response); - } catch (Exception e) { + LOGGER.info(response.toString()); + } catch (ApiException | IOException e) { throw new RuntimeException(e); } - /////////////////////////////////////////////////////// - // Option 3: setting the service account key (and private key) as environment variable - /////////////////////////////////////////////////////// - // Set the service account key via environment variable: - // - STACKIT_SERVICE_ACCOUNT_KEY_PATH=/path/to/sa_key.json - // - STACKIT_SERVICE_ACCOUNT_KEY="" - // - // If the private key is not included in the service account key, set also: - // - STACKIT_PRIVATE_KEY_PATH=/path/to/private_key.pem - // - STACKIT_PRIVATE_KEY="" - // - // If no environment variable is set, fallback to credentials file in - // "$HOME/.stackit/credentials.json". - // Can be overridden with the environment variable `STACKIT_CREDENTIALS_PATH` - // The credentials file must be a json: - // { - // "STACKIT_SERVICE_ACCOUNT_KEY_PATH": "path/to/sa_key.json", - // "STACKIT_PRIVATE_KEY_PATH": "(OPTIONAL) when the private key isn't included in the - // Service Account key", - // // Alternative: - // "STACKIT_SERVICE_ACCOUNT_KEY": "", - // "STACKIT_PRIVATE_KEY": "(OPTIONAL) when the private key isn't included in the Service - // Account key", - // } + /* + * OPTION 3: setting the service account key (and private key) as environment variable + * + * Set the service account key via environment variable: + * - STACKIT_SERVICE_ACCOUNT_KEY_PATH=/path/to/sa_key.json + * - STACKIT_SERVICE_ACCOUNT_KEY="" + * + * If the private key is not included in the service account key, set also: + * - STACKIT_PRIVATE_KEY_PATH=/path/to/private_key.pem + * - STACKIT_PRIVATE_KEY="" + * + * If no environment variable is set, fallback to credentials file in + * "$HOME/.stackit/credentials.json". + * Can be overridden with the environment variable `STACKIT_CREDENTIALS_PATH` + * The credentials file must be a json: + * { + * "STACKIT_SERVICE_ACCOUNT_KEY_PATH": "path/to/sa_key.json", + * "STACKIT_PRIVATE_KEY_PATH": "(OPTIONAL) when the private key isn't included in the + * Service Account key", + * // Alternative: + * "STACKIT_SERVICE_ACCOUNT_KEY": "", + * "STACKIT_PRIVATE_KEY": "(OPTIONAL) when the private key isn't included in the Service + * Account key", + * } + * */ try { ResourceManagerApi api = new ResourceManagerApi(); @@ -115,9 +121,11 @@ public static void main(String[] args) throws IOException { ListOrganizationsResponse response = api.listOrganizations(null, SERVICE_ACCOUNT_MAIL, null, null, null); - System.out.println(response); - } catch (Exception e) { + LOGGER.info(response.toString()); + } catch (ApiException | IOException e) { throw new RuntimeException(e); } } + + private AuthenticationExample() {} } diff --git a/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java b/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java index d3e1600..c2f5158 100644 --- a/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java +++ b/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java @@ -4,31 +4,46 @@ import cloud.stackit.sdk.iaas.api.IaasApi; import cloud.stackit.sdk.iaas.model.*; import java.io.IOException; +import java.net.HttpURLConnection; import java.util.Collections; import java.util.Objects; import java.util.UUID; import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; -public class IaaSExample { +final class IaaSExample { + private static final Logger LOGGER = Logger.getLogger(IaaSExample.class.getName()); + + @SuppressWarnings({ + "PMD.CyclomaticComplexity", + "PMD.CognitiveComplexity", + "PMD.NPathComplexity", + "PMD.NcssCount" + }) public static void main(String[] args) throws IOException { - // Credentials are read from the credentialsFile in `~/.stackit/credentials.json` or the env - // STACKIT_SERVICE_ACCOUNT_KEY_PATH / STACKIT_SERVICE_ACCOUNT_KEY + /* + * Credentials are read from the credentialsFile in `~/.stackit/credentials.json` or the env + * STACKIT_SERVICE_ACCOUNT_KEY_PATH / STACKIT_SERVICE_ACCOUNT_KEY + * */ IaasApi iaasApi = new IaasApi(); // the id of your STACKIT project, read from env var for this example String projectIdString = System.getenv("STACKIT_PROJECT_ID"); if (projectIdString == null || projectIdString.isEmpty()) { - System.err.println("Environment variable 'STACKIT_PROJECT_ID' not found."); + LOGGER.severe("Environment variable 'STACKIT_PROJECT_ID' not found."); return; } UUID projectId = UUID.fromString(projectIdString); try { - /////////////////////////////////////////////////////// - // N E T W O R K S // - /////////////////////////////////////////////////////// + /* + * /////////////////////////////////////////////////////// + * // N E T W O R K S // + * /////////////////////////////////////////////////////// + * */ /* create a network in the project */ + @SuppressWarnings("PMD.AvoidUsingHardCodedIP") Network newNetwork = iaasApi.createNetwork( projectId, @@ -36,7 +51,7 @@ public static void main(String[] args) throws IOException { .name("java-sdk-example-network-01") .dhcp(true) .routed(false) - .labels(Collections.singletonMap("foo", "bar")) + .labels(Collections.singletonMap("some-network-label", "bar")) .addressFamily( new CreateNetworkAddressFamily() .ipv4( @@ -50,34 +65,36 @@ public static void main(String[] args) throws IOException { newNetwork.getNetworkId(), new PartialUpdateNetworkPayload() .dhcp(false) - .labels(Collections.singletonMap("foo", "bar-updated"))); + .labels(Collections.singletonMap("some-network-label", "bar-updated"))); /* fetch the network we just created */ Network fetchedNetwork = iaasApi.getNetwork(projectId, newNetwork.getNetworkId()); - System.out.println("\nFetched network: "); - System.out.println("* Name: " + fetchedNetwork.getName()); - System.out.println("* Id: " + fetchedNetwork.getNetworkId()); - System.out.println( + LOGGER.info("\nFetched network: "); + LOGGER.info("* Network name: " + fetchedNetwork.getName()); + LOGGER.info("* Id: " + fetchedNetwork.getNetworkId()); + LOGGER.info( "* DHCP: " + (Boolean.TRUE.equals(fetchedNetwork.getDhcp()) ? "YES" : "NO")); - System.out.println("* Gateway: " + fetchedNetwork.getGateway()); - System.out.println("* Public IP: " + fetchedNetwork.getPublicIp()); + LOGGER.info("* Gateway: " + fetchedNetwork.getGateway()); + LOGGER.info("* Public IP: " + fetchedNetwork.getPublicIp()); /* list all available networks in the project */ NetworkListResponse networks = iaasApi.listNetworks(projectId, null); - System.out.println("\nAvailable networks: "); + LOGGER.info("\nAvailable networks: "); for (Network network : networks.getItems()) { - System.out.println("* " + network.getName()); + LOGGER.info("* " + network.getName()); } - /////////////////////////////////////////////////////// - // I M A G E S // - /////////////////////////////////////////////////////// + /* + * /////////////////////////////////////////////////////// + * // I M A G E S // + * /////////////////////////////////////////////////////// + * */ /* list all available images */ ImageListResponse images = iaasApi.listImages(projectId, false, null); - System.out.println("\nAvailable images: "); + LOGGER.info("\nAvailable images: "); for (Image image : images.getItems()) { - System.out.println(image.getId() + " | " + image.getName()); + LOGGER.info(image.getId() + " | " + image.getName()); } /* get an image */ @@ -87,22 +104,24 @@ public static void main(String[] args) throws IOException { .getId(); // we just use a random image id in our example assert imageId != null; Image fetchedImage = iaasApi.getImage(projectId, imageId); - System.out.println("\nFetched image:"); - System.out.println("* Name: " + fetchedImage.getName()); - System.out.println("* Id: " + fetchedImage.getId()); - System.out.println("* Checksum: " + fetchedImage.getChecksum()); - System.out.println("* Created at: " + fetchedImage.getCreatedAt()); - System.out.println("* Updated at: " + fetchedImage.getUpdatedAt()); - - /////////////////////////////////////////////////////// - // K E Y P A I R S // - /////////////////////////////////////////////////////// + LOGGER.info("\nFetched image:"); + LOGGER.info("* Image name: " + fetchedImage.getName()); + LOGGER.info("* Image id: " + fetchedImage.getId()); + LOGGER.info("* Checksum: " + fetchedImage.getChecksum()); + LOGGER.info("* Created at: " + fetchedImage.getCreatedAt()); + LOGGER.info("* Updated at: " + fetchedImage.getUpdatedAt()); + + /* + * /////////////////////////////////////////////////////// + * // K E Y P A I R S // + * /////////////////////////////////////////////////////// + * */ /* list all available keypairs */ KeyPairListResponse keypairs = iaasApi.listKeyPairs(null); - System.out.println("\nAvailable keypairs: "); + LOGGER.info("\nAvailable keypairs: "); for (Keypair keypair : keypairs.getItems()) { - System.out.println("* " + keypair.getName()); + LOGGER.info("* " + keypair.getName()); } /* create a keypair */ @@ -113,49 +132,54 @@ public static void main(String[] args) throws IOException { new CreateKeyPairPayload() .name("java-sdk-example-keypair-01") .publicKey(publicKey)); - System.out.println("\nKeypair created: " + newKeypair.getName()); + LOGGER.info("\nKeypair created: " + newKeypair.getName()); /* update the keypair */ assert newKeypair.getName() != null; iaasApi.updateKeyPair( newKeypair.getName(), - new UpdateKeyPairPayload().labels(Collections.singletonMap("foo", "bar"))); + new UpdateKeyPairPayload() + .labels(Collections.singletonMap("some-keypair-label", "bar"))); /* fetch the keypair we just created / updated */ Keypair fetchedKeypair = iaasApi.getKeyPair(newKeypair.getName()); - System.out.println("\nFetched key pair: "); - System.out.println("* Name: " + fetchedKeypair.getName()); + LOGGER.info("\nFetched key pair: "); + LOGGER.info("* Name: " + fetchedKeypair.getName()); if (fetchedKeypair.getLabels() != null) { - System.out.println("* Labels: " + fetchedKeypair.getLabels().toString()); + LOGGER.info("* Labels: " + fetchedKeypair.getLabels().toString()); } - System.out.println("* Fingerprint: " + fetchedKeypair.getFingerprint()); - System.out.println("* Public key: " + fetchedKeypair.getPublicKey()); + LOGGER.info("* Fingerprint: " + fetchedKeypair.getFingerprint()); + LOGGER.info("* Public key: " + fetchedKeypair.getPublicKey()); - /////////////////////////////////////////////////////// - // S E R V E R S // - /////////////////////////////////////////////////////// + /* + * /////////////////////////////////////////////////////// + * // S E R V E R S // + * /////////////////////////////////////////////////////// + * */ /* list all available machine types */ MachineTypeListResponse machineTypes = iaasApi.listMachineTypes(projectId, null); - System.out.println("\nAvailable machine types: "); + LOGGER.info("\nAvailable machine types: "); for (MachineType machineType : machineTypes.getItems()) { - System.out.println("* " + machineType.getName()); + LOGGER.info("* " + machineType.getName()); } /* fetch details about a machine type */ MachineType fetchedMachineType = iaasApi.getMachineType(projectId, machineTypes.getItems().get(0).getName()); - System.out.println("\nFetched machine type: "); - System.out.println("* Name: " + fetchedMachineType.getName()); - System.out.println("* Description: " + fetchedMachineType.getDescription()); - System.out.println("* Disk size: " + fetchedMachineType.getDisk()); - System.out.println("* RAM: " + fetchedMachineType.getRam()); - System.out.println("* vCPUs: " + fetchedMachineType.getVcpus()); - System.out.println("* Extra specs: " + fetchedMachineType.getExtraSpecs()); - - /* create a server */ - // NOTE: see https://docs.stackit.cloud/stackit/en/virtual-machine-flavors-75137231.html - // for available machine types + LOGGER.info("\nFetched machine type: "); + LOGGER.info("* Machine type name: " + fetchedMachineType.getName()); + LOGGER.info("* Description: " + fetchedMachineType.getDescription()); + LOGGER.info("* Disk size: " + fetchedMachineType.getDisk()); + LOGGER.info("* RAM: " + fetchedMachineType.getRam()); + LOGGER.info("* vCPUs: " + fetchedMachineType.getVcpus()); + LOGGER.info("* Extra specs: " + fetchedMachineType.getExtraSpecs()); + + /* + * create a server + * + * NOTE: see https://docs.stackit.cloud/stackit/en/virtual-machine-flavors-75137231.html for available machine types + * */ Server newServer = iaasApi.createServer( projectId, @@ -179,7 +203,7 @@ public static void main(String[] args) throws IOException { assert serverId != null; while (Objects.equals( iaasApi.getServer(projectId, serverId, false).getStatus(), "CREATING")) { - System.out.println("Waiting for server creation to complete ..."); + LOGGER.info("Waiting for server creation to complete ..."); TimeUnit.SECONDS.sleep(5); } @@ -192,30 +216,30 @@ public static void main(String[] args) throws IOException { /* list all servers */ ServerListResponse servers = iaasApi.listServers(projectId, false, null); - System.out.println("\nAvailable servers: "); + LOGGER.info("\nAvailable servers: "); for (Server server : servers.getItems()) { - System.out.println("* " + server.getId() + " | " + server.getName()); + LOGGER.info("* " + server.getId() + " | " + server.getName()); } /* fetch the server we just created */ Server fetchedServer = iaasApi.getServer(projectId, serverId, false); - System.out.println("\nFetched server:"); - System.out.println("* Name: " + fetchedServer.getName()); - System.out.println("* Id: " + fetchedServer.getId()); + LOGGER.info("\nFetched server:"); + LOGGER.info("* Name: " + fetchedServer.getName()); + LOGGER.info("* Id: " + fetchedServer.getId()); if (fetchedServer.getLabels() != null) { - System.out.println("* Labels: " + fetchedServer.getLabels().toString()); + LOGGER.info("* Labels: " + fetchedServer.getLabels().toString()); } - System.out.println("* Machine type: " + fetchedServer.getMachineType()); - System.out.println("* Created at: " + fetchedServer.getCreatedAt()); - System.out.println("* Updated at: " + fetchedServer.getUpdatedAt()); - System.out.println("* Launched at: " + fetchedServer.getLaunchedAt()); + LOGGER.info("* Machine type: " + fetchedServer.getMachineType()); + LOGGER.info("* Created at: " + fetchedServer.getCreatedAt()); + LOGGER.info("* Updated at: " + fetchedServer.getUpdatedAt()); + LOGGER.info("* Launched at: " + fetchedServer.getLaunchedAt()); /* stop the server we just created */ iaasApi.stopServer(projectId, serverId); /* wait for the server to stop */ while (!Objects.equals( iaasApi.getServer(projectId, serverId, false).getPowerStatus(), "STOPPED")) { - System.out.println("Waiting for server " + serverId + " to stop..."); + LOGGER.info("Waiting for server " + serverId + " to stop..."); TimeUnit.SECONDS.sleep(5); } @@ -224,29 +248,31 @@ public static void main(String[] args) throws IOException { /* wait for the server to boot */ while (!Objects.equals( iaasApi.getServer(projectId, serverId, false).getPowerStatus(), "RUNNING")) { - System.out.println("Waiting for server " + serverId + " to boot..."); + LOGGER.info("Waiting for server " + serverId + " to boot..."); TimeUnit.SECONDS.sleep(5); } /* reboot the server we just created */ iaasApi.rebootServer(projectId, serverId, null); - /////////////////////////////////////////////////////// - // D E L E T I O N // - /////////////////////////////////////////////////////// + /* + * /////////////////////////////////////////////////////// + * // D E L E T I O N // + * /////////////////////////////////////////////////////// + * */ /* delete the server we just created */ iaasApi.deleteServer(projectId, serverId); - System.out.println("Deleted server: " + serverId); + LOGGER.info("Deleted server: " + serverId); /* wait for server deletion to complete */ while (true) { try { iaasApi.getServer(projectId, serverId, false); - System.out.println("Waiting for server deletion to complete..."); + LOGGER.info("Waiting for server deletion to complete..."); TimeUnit.SECONDS.sleep(5); } catch (ApiException e) { - if (e.getCode() == 404) { + if (e.getCode() == HttpURLConnection.HTTP_NOT_FOUND) { break; } } @@ -254,14 +280,16 @@ public static void main(String[] args) throws IOException { /* delete the keypair we just created */ iaasApi.deleteKeyPair(newKeypair.getName()); - System.out.println("Deleted key pair: " + newKeypair.getName()); + LOGGER.info("Deleted key pair: " + newKeypair.getName()); /* delete the network we just created */ iaasApi.deleteNetwork(projectId, newNetwork.getNetworkId()); - System.out.println("Deleted network: " + newNetwork.getNetworkId()); + LOGGER.info("Deleted network: " + newNetwork.getNetworkId()); } catch (ApiException | InterruptedException e) { throw new RuntimeException(e); } } + + private IaaSExample() {} } diff --git a/examples/resourcemanager/src/main/java/cloud/stackit/sdk/resourcemanager/examples/ResourcemanagerExample.java b/examples/resourcemanager/src/main/java/cloud/stackit/sdk/resourcemanager/examples/ResourcemanagerExample.java index 34ed2aa..f501c76 100644 --- a/examples/resourcemanager/src/main/java/cloud/stackit/sdk/resourcemanager/examples/ResourcemanagerExample.java +++ b/examples/resourcemanager/src/main/java/cloud/stackit/sdk/resourcemanager/examples/ResourcemanagerExample.java @@ -16,8 +16,11 @@ import java.util.Arrays; import java.util.Collections; import java.util.UUID; +import java.util.logging.Logger; + +final class ResourcemanagerExample { + private static final Logger LOGGER = Logger.getLogger(ResourcemanagerExample.class.getName()); -class ResourcemanagerExample { public static void main(String[] args) throws IOException { // Credentials are read from the credentialsFile in `~/.stackit/credentials.json` or the env // STACKIT_SERVICE_ACCOUNT_KEY_PATH / STACKIT_SERVICE_ACCOUNT_KEY @@ -27,11 +30,11 @@ public static void main(String[] args) throws IOException { String organizationIdString = System.getenv("STACKIT_ORGANIZATION_ID"); String memberSubjectString = System.getenv("STACKIT_MEMBER_SUBJECT"); if (organizationIdString == null || organizationIdString.isEmpty()) { - System.err.println("Environment variable 'STACKIT_ORGANIZATION_ID' not found."); + LOGGER.severe("Environment variable 'STACKIT_ORGANIZATION_ID' not found."); return; } if (memberSubjectString == null || memberSubjectString.isEmpty()) { - System.err.println("Environment variable 'STACKIT_MEMBER_SUBJECT' not found."); + LOGGER.severe("Environment variable 'STACKIT_MEMBER_SUBJECT' not found."); return; } UUID containerParentId = UUID.fromString(organizationIdString); @@ -49,14 +52,16 @@ public static void main(String[] args) throws IOException { .containerParentId(containerParentId.toString()) .name("java-test-project") .addMembersItem(member) - .labels(Collections.singletonMap("foo", "bar"))); - System.out.println("Project:\n" + project.toString()); + .labels( + Collections.singletonMap( + "some-project-label", "foo-bar"))); + LOGGER.info("Project:\n" + project.toString()); /* list projects */ ListProjectsResponse responseListProject = resourceManagerApi.listProjects( organizationIdString, null, null, null, null, null); - System.out.println("Project List:\n" + responseListProject.toString()); + LOGGER.info("Project List:\n" + responseListProject.toString()); /* create a folder */ FolderResponse folder = @@ -65,13 +70,13 @@ public static void main(String[] args) throws IOException { .containerParentId(containerParentId.toString()) .name("java-testing-folder") .labels(Collections.singletonMap("foo", "bar"))); - System.out.println("Folder: \n" + folder.toString()); + LOGGER.info("Folder: \n" + folder.toString()); /* list folders */ ListFoldersResponse responseListFolders = resourceManagerApi.listFolders( organizationIdString, null, null, null, null, null); - System.out.println("Folder List:\n" + responseListFolders.toString()); + LOGGER.info("Folder List:\n" + responseListFolders.toString()); /* delete a project label */ resourceManagerApi.deleteProjectLabels(project.getContainerId(), Arrays.asList("foo")); @@ -93,7 +98,7 @@ public static void main(String[] args) throws IOException { /* get organization details */ OrganizationResponse organizationResponse = resourceManagerApi.getOrganization(organizationIdString); - System.out.println("Organization List:\n" + organizationResponse.toString()); + LOGGER.info("Organization List:\n" + organizationResponse.toString()); /* since you cannot delete a folder when a project is present we need to move the project out again */ resourceManagerApi.partialUpdateProject( @@ -109,4 +114,6 @@ public static void main(String[] args) throws IOException { throw new RuntimeException(e); } } + + private ResourcemanagerExample() {} } From 7a3fb20ae111b832aaaac510f6c90d272c281c4b Mon Sep 17 00:00:00 2001 From: Benjosh95 Date: Thu, 9 Oct 2025 08:41:11 +0200 Subject: [PATCH 02/28] adapt pmd commentsize --- config/pmd/pmd-ruleset.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/config/pmd/pmd-ruleset.xml b/config/pmd/pmd-ruleset.xml index f31a569..cecd912 100644 --- a/config/pmd/pmd-ruleset.xml +++ b/config/pmd/pmd-ruleset.xml @@ -42,6 +42,13 @@ + + + + + + + From 700e0320ea93f25a3219eb63ae667c0fb541f467 Mon Sep 17 00:00:00 2001 From: Benjosh95 Date: Thu, 9 Oct 2025 08:47:57 +0200 Subject: [PATCH 03/28] apply make fmt --- .../stackit/sdk/core/KeyFlowAuthenticator.java | 7 ++----- .../cloud/stackit/sdk/core/auth/SetupAuth.java | 2 +- .../stackit/sdk/core/auth/SetupAuthTest.java | 15 +++++++++------ 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/core/src/main/java/cloud/stackit/sdk/core/KeyFlowAuthenticator.java b/core/src/main/java/cloud/stackit/sdk/core/KeyFlowAuthenticator.java index 1307300..a66d14a 100644 --- a/core/src/main/java/cloud/stackit/sdk/core/KeyFlowAuthenticator.java +++ b/core/src/main/java/cloud/stackit/sdk/core/KeyFlowAuthenticator.java @@ -25,7 +25,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; - import okhttp3.*; import org.jetbrains.annotations.NotNull; @@ -191,8 +190,7 @@ protected String getAccessToken() { * @throws IOException request for new access token failed * @throws ApiException response for new access token with bad status code */ - public String getAccessToken() - throws IOException, ApiException, InvalidKeySpecException { + public String getAccessToken() throws IOException, ApiException, InvalidKeySpecException { try { tokenRefreshLock.lock(); @@ -201,8 +199,7 @@ public String getAccessToken() } else if (token.isExpired()) { createAccessTokenWithRefreshToken(); } - } - finally { + } finally { tokenRefreshLock.unlock(); } diff --git a/core/src/main/java/cloud/stackit/sdk/core/auth/SetupAuth.java b/core/src/main/java/cloud/stackit/sdk/core/auth/SetupAuth.java index fa3a2f5..4ab2e2c 100644 --- a/core/src/main/java/cloud/stackit/sdk/core/auth/SetupAuth.java +++ b/core/src/main/java/cloud/stackit/sdk/core/auth/SetupAuth.java @@ -18,7 +18,6 @@ import java.nio.file.Paths; import java.util.Map; import javax.swing.filechooser.FileSystemView; - import okhttp3.Interceptor; public class SetupAuth { @@ -44,6 +43,7 @@ public class SetupAuth { public SetupAuth() { // deprecated } + // TODO: constructor of SetupAuth should be private after deprecated constructors/methods are // removed (only static methods should remain) diff --git a/core/src/test/java/cloud/stackit/sdk/core/auth/SetupAuthTest.java b/core/src/test/java/cloud/stackit/sdk/core/auth/SetupAuthTest.java index 95ac0c3..3db4186 100644 --- a/core/src/test/java/cloud/stackit/sdk/core/auth/SetupAuthTest.java +++ b/core/src/test/java/cloud/stackit/sdk/core/auth/SetupAuthTest.java @@ -44,7 +44,6 @@ class SetupAuthTest { + File.separator + "file.json"; - private ServiceAccountKey createDummyServiceAccount(String privateKey) { ServiceAccountCredentials credentials = new ServiceAccountCredentials("aud", "iss", "kid", privateKey, "sub"); @@ -81,7 +80,8 @@ void testGetAccessTokenWithoutRunningInitThrowsException() throws IOException { @Test @DisplayName("get access token - with running init - returns interceptor") void testGetAccessTokenWithRunningInitReturnsInterceptor() throws IOException { - ServiceAccountKey saKey = createDummyServiceAccount(TestUtils.MOCK_SERVICE_ACCOUNT_PRIVATE_KEY); + ServiceAccountKey saKey = + createDummyServiceAccount(TestUtils.MOCK_SERVICE_ACCOUNT_PRIVATE_KEY); String initSaKeyJson = new Gson().toJson(saKey); CoreConfiguration config = new CoreConfiguration().serviceAccountKey(initSaKeyJson); @@ -95,7 +95,8 @@ void testGetAccessTokenWithRunningInitReturnsInterceptor() throws IOException { @DisplayName("setup key flow - read service account from path") void setupKeyFlowReadServiceAccountFromPath() throws IOException { // Create service account key file - ServiceAccountKey initSaKey = createDummyServiceAccount(TestUtils.MOCK_SERVICE_ACCOUNT_PRIVATE_KEY); + ServiceAccountKey initSaKey = + createDummyServiceAccount(TestUtils.MOCK_SERVICE_ACCOUNT_PRIVATE_KEY); String initSaKeyJson = new Gson().toJson(initSaKey); Path saKeyPath = Files.createTempFile("serviceAccountKey", JSON_FILE_EXTENSION); saKeyPath.toFile().deleteOnExit(); @@ -114,7 +115,8 @@ void setupKeyFlowReadServiceAccountFromPath() throws IOException { @DisplayName("setup key flow - read service account from config") void setupKeyFlowReadServiceAccountFromConfig() throws IOException { // Create service account key - ServiceAccountKey initSaKey = createDummyServiceAccount(TestUtils.MOCK_SERVICE_ACCOUNT_PRIVATE_KEY); + ServiceAccountKey initSaKey = + createDummyServiceAccount(TestUtils.MOCK_SERVICE_ACCOUNT_PRIVATE_KEY); String initSaKeyJson = new Gson().toJson(initSaKey); // Create config and read setup auth with the previous created saKey @@ -128,7 +130,8 @@ void setupKeyFlowReadServiceAccountFromConfig() throws IOException { @DisplayName("setup key flow - read service account from key env") void setupKeyFlowReadServiceAccountFromKeyEnv() throws IOException { // Create service account key - ServiceAccountKey initSaKey = createDummyServiceAccount(TestUtils.MOCK_SERVICE_ACCOUNT_PRIVATE_KEY); + ServiceAccountKey initSaKey = + createDummyServiceAccount(TestUtils.MOCK_SERVICE_ACCOUNT_PRIVATE_KEY); String initSaKeyJson = new Gson().toJson(initSaKey); // Mock env STACKIT_SERVICE_ACCOUNT_KEY @@ -236,7 +239,7 @@ void loadPrivateKeyDoesNotOverwriteExistingPrivateKey() { @Test @DisplayName("load private key - set private key path") - void loadPrivateKeySetPrivateKeyPath() throws IOException{ + void loadPrivateKeySetPrivateKeyPath() throws IOException { Path tempPrvKeyFile = Files.createTempFile("privateKey", ".pem"); tempPrvKeyFile.toFile().deleteOnExit(); From 5dff990b47ed988111165b1f6b4e718f16f07fb0 Mon Sep 17 00:00:00 2001 From: Benjosh95 Date: Thu, 9 Oct 2025 08:51:39 +0200 Subject: [PATCH 04/28] shorten deprecated comments --- .../main/java/cloud/stackit/sdk/core/auth/SetupAuth.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/cloud/stackit/sdk/core/auth/SetupAuth.java b/core/src/main/java/cloud/stackit/sdk/core/auth/SetupAuth.java index 4ab2e2c..d924277 100644 --- a/core/src/main/java/cloud/stackit/sdk/core/auth/SetupAuth.java +++ b/core/src/main/java/cloud/stackit/sdk/core/auth/SetupAuth.java @@ -64,7 +64,8 @@ public SetupAuth(CoreConfiguration cfg) { } /* - * @deprecated Use static methods of SetupAuth instead or just use the KeyFlowAuthenticator and let it handle the rest. Will be removed in April 2026. + * @deprecated Use static methods of SetupAuth instead or just use the KeyFlowAuthenticator + * and let it handle the rest. Will be removed in April 2026. */ @Deprecated public void init() throws IOException { @@ -73,7 +74,8 @@ public void init() throws IOException { } /* - * @deprecated Use static methods of SetupAuth instead or just use the KeyFlowAuthenticator and let it handle the rest. Will be removed in April 2026. + * @deprecated Use static methods of SetupAuth instead or just use the KeyFlowAuthenticator + * and let it handle the rest. Will be removed in April 2026. */ @Deprecated public Interceptor getAuthHandler() { From 76705470ea4ad752f46522d3207210a7e24eec15 Mon Sep 17 00:00:00 2001 From: Benjosh95 Date: Thu, 9 Oct 2025 09:10:32 +0200 Subject: [PATCH 05/28] fix commentDefaultAccessModifier --- .../main/java/cloud/stackit/sdk/core/KeyFlowAuthenticator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/cloud/stackit/sdk/core/KeyFlowAuthenticator.java b/core/src/main/java/cloud/stackit/sdk/core/KeyFlowAuthenticator.java index a66d14a..1896a9a 100644 --- a/core/src/main/java/cloud/stackit/sdk/core/KeyFlowAuthenticator.java +++ b/core/src/main/java/cloud/stackit/sdk/core/KeyFlowAuthenticator.java @@ -48,7 +48,7 @@ public class KeyFlowAuthenticator implements Authenticator { private final String tokenUrl; private long tokenLeewayInSeconds = DEFAULT_TOKEN_LEEWAY; - Lock tokenRefreshLock = new ReentrantLock(); + private Lock tokenRefreshLock = new ReentrantLock(); /** * Creates the initial service account and refreshes expired access token. From bcf629a85fe42a94f6a6c24e2752bcdddc2e1b74 Mon Sep 17 00:00:00 2001 From: Benjosh95 Date: Thu, 9 Oct 2025 09:12:08 +0200 Subject: [PATCH 06/28] fix pmd ImmutableField --- .../main/java/cloud/stackit/sdk/core/KeyFlowAuthenticator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/cloud/stackit/sdk/core/KeyFlowAuthenticator.java b/core/src/main/java/cloud/stackit/sdk/core/KeyFlowAuthenticator.java index 1896a9a..433ee0f 100644 --- a/core/src/main/java/cloud/stackit/sdk/core/KeyFlowAuthenticator.java +++ b/core/src/main/java/cloud/stackit/sdk/core/KeyFlowAuthenticator.java @@ -48,7 +48,7 @@ public class KeyFlowAuthenticator implements Authenticator { private final String tokenUrl; private long tokenLeewayInSeconds = DEFAULT_TOKEN_LEEWAY; - private Lock tokenRefreshLock = new ReentrantLock(); + private final Lock tokenRefreshLock = new ReentrantLock(); /** * Creates the initial service account and refreshes expired access token. From 2e0f841b26c77c7da2b6d36111a52f25ddff7f5a Mon Sep 17 00:00:00 2001 From: Benjosh95 Date: Thu, 9 Oct 2025 10:45:25 +0200 Subject: [PATCH 07/28] fix pmd AvoidUncheckedExceptionsInSignatures --- .../sdk/core/KeyFlowAuthenticator.java | 13 +++++-- .../stackit/sdk/core/auth/SetupAuth.java | 34 ++++++++++++++----- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/cloud/stackit/sdk/core/KeyFlowAuthenticator.java b/core/src/main/java/cloud/stackit/sdk/core/KeyFlowAuthenticator.java index 433ee0f..8b8e381 100644 --- a/core/src/main/java/cloud/stackit/sdk/core/KeyFlowAuthenticator.java +++ b/core/src/main/java/cloud/stackit/sdk/core/KeyFlowAuthenticator.java @@ -215,7 +215,7 @@ public String getAccessToken() throws IOException, ApiException, InvalidKeySpecE * @throws JsonSyntaxException parsing of the created access token failed */ protected void createAccessToken() - throws InvalidKeySpecException, IOException, JsonSyntaxException, ApiException { + throws InvalidKeySpecException, IOException, ApiException { String assertion; try { assertion = generateSelfSignedJWT(); @@ -239,15 +239,22 @@ protected void createAccessToken() * @throws JsonSyntaxException can not parse new access token */ protected synchronized void createAccessTokenWithRefreshToken() - throws IOException, JsonSyntaxException, ApiException { + throws IOException, ApiException { String refreshToken = token.refreshToken; try (Response response = requestToken(REFRESH_TOKEN, refreshToken).execute()) { parseTokenResponse(response); } } + /** + * Parses the token response from the server + * + * @param response HTTP response containing the token + * @throws ApiException if the response has a bad status code + * @throws JsonSyntaxException if the response body cannot be parsed + */ private synchronized void parseTokenResponse(Response response) - throws ApiException, JsonSyntaxException { + throws ApiException { if (response.code() != HttpURLConnection.HTTP_OK) { String body = null; if (response.body() != null) { diff --git a/core/src/main/java/cloud/stackit/sdk/core/auth/SetupAuth.java b/core/src/main/java/cloud/stackit/sdk/core/auth/SetupAuth.java index d924277..9c09811 100644 --- a/core/src/main/java/cloud/stackit/sdk/core/auth/SetupAuth.java +++ b/core/src/main/java/cloud/stackit/sdk/core/auth/SetupAuth.java @@ -126,12 +126,22 @@ private static String getDefaultCredentialsFilePath() { * @throws IOException thrown when a file can not be found */ public static ServiceAccountKey setupKeyFlow(CoreConfiguration cfg) - throws CredentialsInFileNotFoundException, IOException { + throws IOException { return setupKeyFlow(cfg, new EnvironmentVariables()); } + /** + * Sets up the KeyFlow Authentication + * + * @param cfg Configuration + * @param env Environment variables + * @return Service account key + * @throws CredentialsInFileNotFoundException thrown when no service account key or private key + * can be found + * @throws IOException thrown when a file can not be found + */ protected static ServiceAccountKey setupKeyFlow(CoreConfiguration cfg, EnvironmentVariables env) - throws CredentialsInFileNotFoundException, IOException { + throws IOException { // Explicit config in code if (Utils.isStringSet(cfg.getServiceAccountKey())) { ServiceAccountKey saKey = ServiceAccountKey.loadFromJson(cfg.getServiceAccountKey()); @@ -184,13 +194,21 @@ protected static ServiceAccountKey setupKeyFlow(CoreConfiguration cfg, Environme return saKey; } + /** + * Loads the private key into the service account key + * + * @param cfg Configuration + * @param env Environment variables + * @param saKey Service account key + * @throws PrivateKeyNotFoundException if the private key could not be found + */ protected static void loadPrivateKey( - CoreConfiguration cfg, EnvironmentVariables env, ServiceAccountKey saKey) - throws PrivateKeyNotFoundException { - if (!saKey.getCredentials().isPrivateKeySet()) { + CoreConfiguration cfg, EnvironmentVariables env, ServiceAccountKey saKey) { + ServiceAccountCredentials credentials = saKey.getCredentials(); + if (!credentials.isPrivateKeySet()) { try { String privateKey = getPrivateKey(cfg, env); - saKey.getCredentials().setPrivateKey(privateKey); + credentials.setPrivateKey(privateKey); } catch (CredentialsInFileNotFoundException | IOException e) { throw new PrivateKeyNotFoundException("could not find private key", e); } @@ -228,7 +246,7 @@ protected static void loadPrivateKey( * pathKey can not be found */ private static String getPrivateKey(CoreConfiguration cfg, EnvironmentVariables env) - throws CredentialsInFileNotFoundException, IOException { + throws IOException { // Explicit code config // Get private key if (Utils.isStringSet(cfg.getPrivateKey())) { @@ -286,7 +304,7 @@ private static String getPrivateKey(CoreConfiguration cfg, EnvironmentVariables */ protected static String readValueFromCredentialsFile( String path, String valueKey, String pathKey) - throws IOException, CredentialsInFileNotFoundException { + throws IOException { // Read credentials file String fileContent = new String(Files.readAllBytes(Paths.get(path)), StandardCharsets.UTF_8); From dc61aa0ee390cfa979386a7c1e22a48300a053ec Mon Sep 17 00:00:00 2001 From: Benjosh95 Date: Thu, 9 Oct 2025 11:24:28 +0200 Subject: [PATCH 08/28] fix pmd AvoidThrowingRawExceptionTypes --- .../java/cloud/stackit/sdk/core/KeyFlowAuthenticator.java | 4 ++-- .../main/java/cloud/stackit/sdk/core/KeyFlowInterceptor.java | 2 +- core/src/main/java/cloud/stackit/sdk/core/auth/SetupAuth.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/cloud/stackit/sdk/core/KeyFlowAuthenticator.java b/core/src/main/java/cloud/stackit/sdk/core/KeyFlowAuthenticator.java index 8b8e381..208a7b5 100644 --- a/core/src/main/java/cloud/stackit/sdk/core/KeyFlowAuthenticator.java +++ b/core/src/main/java/cloud/stackit/sdk/core/KeyFlowAuthenticator.java @@ -134,7 +134,7 @@ public Request authenticate(Route route, @NotNull Response response) throws IOEx try { accessToken = getAccessToken(); } catch (ApiException | InvalidKeySpecException e) { - throw new RuntimeException(e); + throw new IllegalStateException(e); } // Return a new request with the refreshed token @@ -220,7 +220,7 @@ protected void createAccessToken() try { assertion = generateSelfSignedJWT(); } catch (NoSuchAlgorithmException e) { - throw new RuntimeException( + throw new IllegalStateException( "could not find required algorithm for jwt signing. This should not happen and should be reported on https://github.com/stackitcloud/stackit-sdk-java/issues", e); } diff --git a/core/src/main/java/cloud/stackit/sdk/core/KeyFlowInterceptor.java b/core/src/main/java/cloud/stackit/sdk/core/KeyFlowInterceptor.java index d310489..63461e9 100644 --- a/core/src/main/java/cloud/stackit/sdk/core/KeyFlowInterceptor.java +++ b/core/src/main/java/cloud/stackit/sdk/core/KeyFlowInterceptor.java @@ -37,7 +37,7 @@ public Response intercept(Chain chain) throws IOException { } catch (InvalidKeySpecException | ApiException e) { // try-catch required, because ApiException can not be thrown in the implementation // of Interceptor.intercept(Chain chain) - throw new RuntimeException(e); + throw new IllegalStateException(e); } Request authenticatedRequest = diff --git a/core/src/main/java/cloud/stackit/sdk/core/auth/SetupAuth.java b/core/src/main/java/cloud/stackit/sdk/core/auth/SetupAuth.java index 9c09811..48c9495 100644 --- a/core/src/main/java/cloud/stackit/sdk/core/auth/SetupAuth.java +++ b/core/src/main/java/cloud/stackit/sdk/core/auth/SetupAuth.java @@ -80,7 +80,7 @@ public void init() throws IOException { @Deprecated public Interceptor getAuthHandler() { if (authHandler == null) { - throw new RuntimeException("init() has to be called first"); + throw new IllegalStateException("init() has to be called first"); } return authHandler; } From fba346937ec0bd9d6717f405f82fa3ea872d2f54 Mon Sep 17 00:00:00 2001 From: Benjosh95 Date: Thu, 9 Oct 2025 12:59:52 +0200 Subject: [PATCH 09/28] fix pmd avoidsynchronized statement or method --- .../sdk/core/KeyFlowAuthenticator.java | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/core/src/main/java/cloud/stackit/sdk/core/KeyFlowAuthenticator.java b/core/src/main/java/cloud/stackit/sdk/core/KeyFlowAuthenticator.java index 208a7b5..aaf44c8 100644 --- a/core/src/main/java/cloud/stackit/sdk/core/KeyFlowAuthenticator.java +++ b/core/src/main/java/cloud/stackit/sdk/core/KeyFlowAuthenticator.java @@ -23,8 +23,6 @@ import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; import okhttp3.*; import org.jetbrains.annotations.NotNull; @@ -48,7 +46,7 @@ public class KeyFlowAuthenticator implements Authenticator { private final String tokenUrl; private long tokenLeewayInSeconds = DEFAULT_TOKEN_LEEWAY; - private final Lock tokenRefreshLock = new ReentrantLock(); + private final Object tokenRefreshMonitor = new Object(); /** * Creates the initial service account and refreshes expired access token. @@ -190,20 +188,16 @@ protected String getAccessToken() { * @throws IOException request for new access token failed * @throws ApiException response for new access token with bad status code */ + @SuppressWarnings("PMD.AvoidSynchronizedStatement") public String getAccessToken() throws IOException, ApiException, InvalidKeySpecException { - try { - tokenRefreshLock.lock(); - + synchronized (tokenRefreshMonitor) { if (token == null) { createAccessToken(); } else if (token.isExpired()) { createAccessTokenWithRefreshToken(); } - } finally { - tokenRefreshLock.unlock(); + return token.getAccessToken(); } - - return token.getAccessToken(); } /** @@ -214,20 +208,23 @@ public String getAccessToken() throws IOException, ApiException, InvalidKeySpecE * @throws ApiException response for new access token with bad status code * @throws JsonSyntaxException parsing of the created access token failed */ + @SuppressWarnings("PMD.AvoidSynchronizedStatement") protected void createAccessToken() throws InvalidKeySpecException, IOException, ApiException { - String assertion; - try { - assertion = generateSelfSignedJWT(); - } catch (NoSuchAlgorithmException e) { - throw new IllegalStateException( - "could not find required algorithm for jwt signing. This should not happen and should be reported on https://github.com/stackitcloud/stackit-sdk-java/issues", - e); - } + synchronized (tokenRefreshMonitor) { + String assertion; + try { + assertion = generateSelfSignedJWT(); + } catch (NoSuchAlgorithmException e) { + throw new IllegalStateException( + "could not find required algorithm for jwt signing. This should not happen and should be reported on https://github.com/stackitcloud/stackit-sdk-java/issues", + e); + } - String grant = "urn:ietf:params:oauth:grant-type:jwt-bearer"; - try (Response response = requestToken(grant, assertion).execute()) { - parseTokenResponse(response); + String grant = "urn:ietf:params:oauth:grant-type:jwt-bearer"; + try (Response response = requestToken(grant, assertion).execute()) { + parseTokenResponse(response); + } } } @@ -238,11 +235,14 @@ protected void createAccessToken() * @throws ApiException response for new access token with bad status code * @throws JsonSyntaxException can not parse new access token */ - protected synchronized void createAccessTokenWithRefreshToken() + @SuppressWarnings("PMD.AvoidSynchronizedStatement") + protected void createAccessTokenWithRefreshToken() throws IOException, ApiException { - String refreshToken = token.refreshToken; - try (Response response = requestToken(REFRESH_TOKEN, refreshToken).execute()) { - parseTokenResponse(response); + synchronized (tokenRefreshMonitor) { + String refreshToken = token.refreshToken; + try (Response response = requestToken(REFRESH_TOKEN, refreshToken).execute()) { + parseTokenResponse(response); + } } } @@ -253,7 +253,7 @@ protected synchronized void createAccessTokenWithRefreshToken() * @throws ApiException if the response has a bad status code * @throws JsonSyntaxException if the response body cannot be parsed */ - private synchronized void parseTokenResponse(Response response) + private void parseTokenResponse(Response response) throws ApiException { if (response.code() != HttpURLConnection.HTTP_OK) { String body = null; From 62c44e09d52921cfa67af67ff42116575b115ba9 Mon Sep 17 00:00:00 2001 From: Benjosh95 Date: Thu, 9 Oct 2025 13:53:36 +0200 Subject: [PATCH 10/28] fix pmd law-of-demeter in ruleset --- config/pmd/pmd-ruleset.xml | 3 +++ core/src/main/java/cloud/stackit/sdk/core/auth/SetupAuth.java | 1 + 2 files changed, 4 insertions(+) diff --git a/config/pmd/pmd-ruleset.xml b/config/pmd/pmd-ruleset.xml index cecd912..7c1187b 100644 --- a/config/pmd/pmd-ruleset.xml +++ b/config/pmd/pmd-ruleset.xml @@ -35,7 +35,10 @@ + + diff --git a/core/src/main/java/cloud/stackit/sdk/core/auth/SetupAuth.java b/core/src/main/java/cloud/stackit/sdk/core/auth/SetupAuth.java index 48c9495..9ecde65 100644 --- a/core/src/main/java/cloud/stackit/sdk/core/auth/SetupAuth.java +++ b/core/src/main/java/cloud/stackit/sdk/core/auth/SetupAuth.java @@ -6,6 +6,7 @@ import cloud.stackit.sdk.core.config.EnvironmentVariables; import cloud.stackit.sdk.core.exception.CredentialsInFileNotFoundException; import cloud.stackit.sdk.core.exception.PrivateKeyNotFoundException; +import cloud.stackit.sdk.core.model.ServiceAccountCredentials; import cloud.stackit.sdk.core.model.ServiceAccountKey; import cloud.stackit.sdk.core.utils.Utils; import com.google.gson.Gson; From d7aec545588494622959e8b3b2248d18a4a182d7 Mon Sep 17 00:00:00 2001 From: Benjosh95 Date: Thu, 9 Oct 2025 19:15:51 +0200 Subject: [PATCH 11/28] fix pmd GuardLogStatement --- .../examples/AuthenticationExample.java | 13 +- .../sdk/iaas/examples/IaaSExample.java | 148 +++++++++++------- .../examples/ResourcemanagerExample.java | 21 ++- 3 files changed, 117 insertions(+), 65 deletions(-) diff --git a/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java b/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java index 7715447..eebb0e2 100644 --- a/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java +++ b/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java @@ -8,6 +8,7 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.util.Scanner; +import java.util.logging.Level; import java.util.logging.Logger; final class AuthenticationExample { @@ -32,7 +33,9 @@ public static void main(String[] args) { ListOrganizationsResponse response = api.listOrganizations(null, SERVICE_ACCOUNT_MAIL, null, null, null); - LOGGER.info(response.toString()); + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info(response.toString()); + } } catch (ApiException | IOException e) { throw new RuntimeException(e); } @@ -84,7 +87,9 @@ public static void main(String[] args) { ListOrganizationsResponse response = api.listOrganizations(null, SERVICE_ACCOUNT_MAIL, null, null, null); - LOGGER.info(response.toString()); + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info(response.toString()); + } } catch (ApiException | IOException e) { throw new RuntimeException(e); } @@ -121,7 +126,9 @@ public static void main(String[] args) { ListOrganizationsResponse response = api.listOrganizations(null, SERVICE_ACCOUNT_MAIL, null, null, null); - LOGGER.info(response.toString()); + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info(response.toString()); + } } catch (ApiException | IOException e) { throw new RuntimeException(e); } diff --git a/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java b/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java index c2f5158..114bdaf 100644 --- a/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java +++ b/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java @@ -9,6 +9,7 @@ import java.util.Objects; import java.util.UUID; import java.util.concurrent.TimeUnit; +import java.util.logging.Level; import java.util.logging.Logger; final class IaaSExample { @@ -69,19 +70,22 @@ public static void main(String[] args) throws IOException { /* fetch the network we just created */ Network fetchedNetwork = iaasApi.getNetwork(projectId, newNetwork.getNetworkId()); - LOGGER.info("\nFetched network: "); - LOGGER.info("* Network name: " + fetchedNetwork.getName()); - LOGGER.info("* Id: " + fetchedNetwork.getNetworkId()); - LOGGER.info( - "* DHCP: " + (Boolean.TRUE.equals(fetchedNetwork.getDhcp()) ? "YES" : "NO")); - LOGGER.info("* Gateway: " + fetchedNetwork.getGateway()); - LOGGER.info("* Public IP: " + fetchedNetwork.getPublicIp()); + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info("\nFetched network: "); + LOGGER.info("* Network name: " + fetchedNetwork.getName()); + LOGGER.info("* Id: " + fetchedNetwork.getNetworkId()); + LOGGER.info("* DHCP: " + (Boolean.TRUE.equals(fetchedNetwork.getDhcp()) ? "YES" : "NO")); + LOGGER.info("* Gateway: " + fetchedNetwork.getGateway()); + LOGGER.info("* Public IP: " + fetchedNetwork.getPublicIp()); + } /* list all available networks in the project */ NetworkListResponse networks = iaasApi.listNetworks(projectId, null); - LOGGER.info("\nAvailable networks: "); - for (Network network : networks.getItems()) { - LOGGER.info("* " + network.getName()); + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info("\nAvailable networks: "); + for (Network network : networks.getItems()) { + LOGGER.info("* " + network.getName()); + } } /* @@ -92,9 +96,11 @@ public static void main(String[] args) throws IOException { /* list all available images */ ImageListResponse images = iaasApi.listImages(projectId, false, null); - LOGGER.info("\nAvailable images: "); - for (Image image : images.getItems()) { - LOGGER.info(image.getId() + " | " + image.getName()); + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info("\nAvailable images: "); + for (Image image : images.getItems()) { + LOGGER.info(image.getId() + " | " + image.getName()); + } } /* get an image */ @@ -104,12 +110,14 @@ public static void main(String[] args) throws IOException { .getId(); // we just use a random image id in our example assert imageId != null; Image fetchedImage = iaasApi.getImage(projectId, imageId); - LOGGER.info("\nFetched image:"); - LOGGER.info("* Image name: " + fetchedImage.getName()); - LOGGER.info("* Image id: " + fetchedImage.getId()); - LOGGER.info("* Checksum: " + fetchedImage.getChecksum()); - LOGGER.info("* Created at: " + fetchedImage.getCreatedAt()); - LOGGER.info("* Updated at: " + fetchedImage.getUpdatedAt()); + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info("\nFetched image:"); + LOGGER.info("* Image name: " + fetchedImage.getName()); + LOGGER.info("* Image id: " + fetchedImage.getId()); + LOGGER.info("* Checksum: " + fetchedImage.getChecksum()); + LOGGER.info("* Created at: " + fetchedImage.getCreatedAt()); + LOGGER.info("* Updated at: " + fetchedImage.getUpdatedAt()); + } /* * /////////////////////////////////////////////////////// @@ -119,9 +127,11 @@ public static void main(String[] args) throws IOException { /* list all available keypairs */ KeyPairListResponse keypairs = iaasApi.listKeyPairs(null); - LOGGER.info("\nAvailable keypairs: "); - for (Keypair keypair : keypairs.getItems()) { - LOGGER.info("* " + keypair.getName()); + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info("\nAvailable keypairs: "); + for (Keypair keypair : keypairs.getItems()) { + LOGGER.info("* " + keypair.getName()); + } } /* create a keypair */ @@ -132,7 +142,9 @@ public static void main(String[] args) throws IOException { new CreateKeyPairPayload() .name("java-sdk-example-keypair-01") .publicKey(publicKey)); - LOGGER.info("\nKeypair created: " + newKeypair.getName()); + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info("\nKeypair created: " + newKeypair.getName()); + } /* update the keypair */ assert newKeypair.getName() != null; @@ -143,13 +155,15 @@ public static void main(String[] args) throws IOException { /* fetch the keypair we just created / updated */ Keypair fetchedKeypair = iaasApi.getKeyPair(newKeypair.getName()); - LOGGER.info("\nFetched key pair: "); - LOGGER.info("* Name: " + fetchedKeypair.getName()); - if (fetchedKeypair.getLabels() != null) { - LOGGER.info("* Labels: " + fetchedKeypair.getLabels().toString()); + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info("\nFetched key pair: "); + LOGGER.info("* Name: " + fetchedKeypair.getName()); + if (fetchedKeypair.getLabels() != null) { + LOGGER.info("* Labels: " + fetchedKeypair.getLabels().toString()); // NOPMD GuardLogStatement + } + LOGGER.info("* Fingerprint: " + fetchedKeypair.getFingerprint()); + LOGGER.info("* Public key: " + fetchedKeypair.getPublicKey()); } - LOGGER.info("* Fingerprint: " + fetchedKeypair.getFingerprint()); - LOGGER.info("* Public key: " + fetchedKeypair.getPublicKey()); /* * /////////////////////////////////////////////////////// @@ -159,21 +173,25 @@ public static void main(String[] args) throws IOException { /* list all available machine types */ MachineTypeListResponse machineTypes = iaasApi.listMachineTypes(projectId, null); - LOGGER.info("\nAvailable machine types: "); - for (MachineType machineType : machineTypes.getItems()) { - LOGGER.info("* " + machineType.getName()); + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info("\nAvailable machine types: "); + for (MachineType machineType : machineTypes.getItems()) { + LOGGER.info("* " + machineType.getName()); + } } /* fetch details about a machine type */ MachineType fetchedMachineType = iaasApi.getMachineType(projectId, machineTypes.getItems().get(0).getName()); - LOGGER.info("\nFetched machine type: "); - LOGGER.info("* Machine type name: " + fetchedMachineType.getName()); - LOGGER.info("* Description: " + fetchedMachineType.getDescription()); - LOGGER.info("* Disk size: " + fetchedMachineType.getDisk()); - LOGGER.info("* RAM: " + fetchedMachineType.getRam()); - LOGGER.info("* vCPUs: " + fetchedMachineType.getVcpus()); - LOGGER.info("* Extra specs: " + fetchedMachineType.getExtraSpecs()); + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info("\nFetched machine type: "); + LOGGER.info("* Machine type name: " + fetchedMachineType.getName()); + LOGGER.info("* Description: " + fetchedMachineType.getDescription()); + LOGGER.info("* Disk size: " + fetchedMachineType.getDisk()); + LOGGER.info("* RAM: " + fetchedMachineType.getRam()); + LOGGER.info("* vCPUs: " + fetchedMachineType.getVcpus()); + LOGGER.info("* Extra specs: " + fetchedMachineType.getExtraSpecs()); + } /* * create a server @@ -216,30 +234,36 @@ public static void main(String[] args) throws IOException { /* list all servers */ ServerListResponse servers = iaasApi.listServers(projectId, false, null); - LOGGER.info("\nAvailable servers: "); - for (Server server : servers.getItems()) { - LOGGER.info("* " + server.getId() + " | " + server.getName()); + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info("\nAvailable servers: "); + for (Server server : servers.getItems()) { + LOGGER.info("* " + server.getId() + " | " + server.getName()); + } } /* fetch the server we just created */ Server fetchedServer = iaasApi.getServer(projectId, serverId, false); - LOGGER.info("\nFetched server:"); - LOGGER.info("* Name: " + fetchedServer.getName()); - LOGGER.info("* Id: " + fetchedServer.getId()); - if (fetchedServer.getLabels() != null) { - LOGGER.info("* Labels: " + fetchedServer.getLabels().toString()); + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info("\nFetched server:"); + LOGGER.info("* Name: " + fetchedServer.getName()); + LOGGER.info("* Id: " + fetchedServer.getId()); + if (fetchedServer.getLabels() != null) { + LOGGER.info("* Labels: " + fetchedServer.getLabels().toString()); // NOPMD GuardLogStatement + } + LOGGER.info("* Machine type: " + fetchedServer.getMachineType()); + LOGGER.info("* Created at: " + fetchedServer.getCreatedAt()); + LOGGER.info("* Updated at: " + fetchedServer.getUpdatedAt()); + LOGGER.info("* Launched at: " + fetchedServer.getLaunchedAt()); } - LOGGER.info("* Machine type: " + fetchedServer.getMachineType()); - LOGGER.info("* Created at: " + fetchedServer.getCreatedAt()); - LOGGER.info("* Updated at: " + fetchedServer.getUpdatedAt()); - LOGGER.info("* Launched at: " + fetchedServer.getLaunchedAt()); /* stop the server we just created */ iaasApi.stopServer(projectId, serverId); /* wait for the server to stop */ while (!Objects.equals( iaasApi.getServer(projectId, serverId, false).getPowerStatus(), "STOPPED")) { - LOGGER.info("Waiting for server " + serverId + " to stop..."); + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info("Waiting for server " + serverId + " to stop..."); + } TimeUnit.SECONDS.sleep(5); } @@ -248,7 +272,9 @@ public static void main(String[] args) throws IOException { /* wait for the server to boot */ while (!Objects.equals( iaasApi.getServer(projectId, serverId, false).getPowerStatus(), "RUNNING")) { - LOGGER.info("Waiting for server " + serverId + " to boot..."); + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info("Waiting for server " + serverId + " to boot..."); + } TimeUnit.SECONDS.sleep(5); } @@ -263,13 +289,17 @@ public static void main(String[] args) throws IOException { /* delete the server we just created */ iaasApi.deleteServer(projectId, serverId); - LOGGER.info("Deleted server: " + serverId); + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info("Deleted server: " + serverId); + } /* wait for server deletion to complete */ while (true) { try { iaasApi.getServer(projectId, serverId, false); - LOGGER.info("Waiting for server deletion to complete..."); + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info("Waiting for server deletion to complete..."); + } TimeUnit.SECONDS.sleep(5); } catch (ApiException e) { if (e.getCode() == HttpURLConnection.HTTP_NOT_FOUND) { @@ -280,11 +310,15 @@ public static void main(String[] args) throws IOException { /* delete the keypair we just created */ iaasApi.deleteKeyPair(newKeypair.getName()); - LOGGER.info("Deleted key pair: " + newKeypair.getName()); + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info("Deleted key pair: " + newKeypair.getName()); + } /* delete the network we just created */ iaasApi.deleteNetwork(projectId, newNetwork.getNetworkId()); - LOGGER.info("Deleted network: " + newNetwork.getNetworkId()); + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info("Deleted network: " + newNetwork.getNetworkId()); + } } catch (ApiException | InterruptedException e) { throw new RuntimeException(e); diff --git a/examples/resourcemanager/src/main/java/cloud/stackit/sdk/resourcemanager/examples/ResourcemanagerExample.java b/examples/resourcemanager/src/main/java/cloud/stackit/sdk/resourcemanager/examples/ResourcemanagerExample.java index f501c76..57be3bf 100644 --- a/examples/resourcemanager/src/main/java/cloud/stackit/sdk/resourcemanager/examples/ResourcemanagerExample.java +++ b/examples/resourcemanager/src/main/java/cloud/stackit/sdk/resourcemanager/examples/ResourcemanagerExample.java @@ -16,6 +16,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.UUID; +import java.util.logging.Level; import java.util.logging.Logger; final class ResourcemanagerExample { @@ -55,13 +56,17 @@ public static void main(String[] args) throws IOException { .labels( Collections.singletonMap( "some-project-label", "foo-bar"))); - LOGGER.info("Project:\n" + project.toString()); + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info("Project:\n" + project.toString()); + } /* list projects */ ListProjectsResponse responseListProject = resourceManagerApi.listProjects( organizationIdString, null, null, null, null, null); - LOGGER.info("Project List:\n" + responseListProject.toString()); + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info("Project List:\n" + responseListProject.toString()); + } /* create a folder */ FolderResponse folder = @@ -70,13 +75,17 @@ public static void main(String[] args) throws IOException { .containerParentId(containerParentId.toString()) .name("java-testing-folder") .labels(Collections.singletonMap("foo", "bar"))); - LOGGER.info("Folder: \n" + folder.toString()); + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info("Folder: \n" + folder.toString()); + } /* list folders */ ListFoldersResponse responseListFolders = resourceManagerApi.listFolders( organizationIdString, null, null, null, null, null); - LOGGER.info("Folder List:\n" + responseListFolders.toString()); + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info("Folder List:\n" + responseListFolders.toString()); + } /* delete a project label */ resourceManagerApi.deleteProjectLabels(project.getContainerId(), Arrays.asList("foo")); @@ -98,7 +107,9 @@ public static void main(String[] args) throws IOException { /* get organization details */ OrganizationResponse organizationResponse = resourceManagerApi.getOrganization(organizationIdString); - LOGGER.info("Organization List:\n" + organizationResponse.toString()); + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info("Organization List:\n" + organizationResponse.toString()); + } /* since you cannot delete a folder when a project is present we need to move the project out again */ resourceManagerApi.partialUpdateProject( From c6b1de5e2c013a99aaa7984e69596134fe2d2c89 Mon Sep 17 00:00:00 2001 From: Benjosh95 Date: Thu, 9 Oct 2025 19:22:05 +0200 Subject: [PATCH 12/28] fix pmd commentsize --- .../customhttpclient/examples/CustomHttpClientExample.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java b/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java index 7ce4577..04d2779 100644 --- a/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java +++ b/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java @@ -14,10 +14,11 @@ * * The example shows how to set the authorization header in the OkHttpClient object (required!). * - * NOTE: Passing the http client is optional, see our other examples where no OkHttpClient object is passed. + * NOTE: Passing the http client is optional, see our other examples + * where no OkHttpClient object is passed. * In this case the STACKIT SDK ApiClients will just create their own OkHttpClient objects. - * Nevertheless, for production usage try to use one single OkHttpClient object for everything to take advantage of the - * shared connection pool and to prevent resource leaks. + * Nevertheless, for production usage try to use one single OkHttpClient object + * for everything to take advantage of the shared connection pool and to prevent resource leaks. * * */ public class CustomHttpClientExample { From 92c9c3fcb83f063bb49c9c7771c90cf2f56c37ed Mon Sep 17 00:00:00 2001 From: Benjosh95 Date: Thu, 9 Oct 2025 19:41:21 +0200 Subject: [PATCH 13/28] fix pmd SystemPrintln --- .../examples/CustomHttpClientExample.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java b/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java index 04d2779..626796a 100644 --- a/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java +++ b/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java @@ -7,6 +7,8 @@ import cloud.stackit.sdk.iaas.model.*; import java.io.IOException; import java.util.UUID; +import java.util.logging.Level; +import java.util.logging.Logger; import okhttp3.OkHttpClient; /* @@ -22,6 +24,8 @@ * * */ public class CustomHttpClientExample { + private static final Logger LOGGER = Logger.getLogger(CustomHttpClientExample.class.getName()); + public static void main(String[] args) throws IOException { // Credentials are read from the credentialsFile in `~/.stackit/credentials.json` or the env // STACKIT_SERVICE_ACCOUNT_KEY_PATH / STACKIT_SERVICE_ACCOUNT_KEY @@ -37,7 +41,7 @@ public static void main(String[] args) throws IOException { // the id of your STACKIT project, read from env var for this example String projectIdString = System.getenv("STACKIT_PROJECT_ID"); if (projectIdString == null || projectIdString.isEmpty()) { - System.err.println("Environment variable 'STACKIT_PROJECT_ID' not found."); + LOGGER.severe("Environment variable 'STACKIT_PROJECT_ID' not found."); return; } UUID projectId = UUID.fromString(projectIdString); @@ -45,9 +49,11 @@ public static void main(String[] args) throws IOException { try { /* list all servers */ ServerListResponse servers = iaasApi.listServers(projectId, false, null); - System.out.println("\nAvailable servers: "); - for (Server server : servers.getItems()) { - System.out.println("* " + server.getId() + " | " + server.getName()); + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info("\nAvailable servers: "); + for (Server server : servers.getItems()) { + LOGGER.info("* " + server.getId() + " | " + server.getName()); + } } } catch (ApiException e) { throw new RuntimeException(e); From 4c988e1bf6def76787407a9f0da659cc18523be8 Mon Sep 17 00:00:00 2001 From: Benjosh95 Date: Thu, 9 Oct 2025 19:43:49 +0200 Subject: [PATCH 14/28] fix pmd commentsize --- .../sdk/authentication/examples/AuthenticationExample.java | 4 +++- .../java/cloud/stackit/sdk/iaas/examples/IaaSExample.java | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java b/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java index eebb0e2..8193377 100644 --- a/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java +++ b/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java @@ -45,7 +45,9 @@ public static void main(String[] args) { * * */ - /* read key content from a file, in production you can also read it e.g. from STACKIT secrets manager, so it's only kept in-memory */ + /* read key content from a file, in production you can also read it + * e.g. from STACKIT secrets manager, so it's only kept in-memory + * */ String serviceAccountKeyPath = // replace it with the path to your service account key "examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/dummy_credentials/dummy-service-account-key.json"; File serviceAccountKeyFile = new File(serviceAccountKeyPath); diff --git a/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java b/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java index 114bdaf..f24b48d 100644 --- a/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java +++ b/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java @@ -196,7 +196,8 @@ public static void main(String[] args) throws IOException { /* * create a server * - * NOTE: see https://docs.stackit.cloud/stackit/en/virtual-machine-flavors-75137231.html for available machine types + * NOTE: https://docs.stackit.cloud/stackit/en/virtual-machine-flavors-75137231.html + * for available machine types * */ Server newServer = iaasApi.createServer( From 26134b33d59c407c9c2ea33f39f8a4351bf6a69e Mon Sep 17 00:00:00 2001 From: Benjosh95 Date: Thu, 9 Oct 2025 19:46:24 +0200 Subject: [PATCH 15/28] fix pmd commentsize --- .../java/cloud/stackit/sdk/iaas/examples/IaaSExample.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java b/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java index f24b48d..8987aac 100644 --- a/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java +++ b/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java @@ -196,8 +196,9 @@ public static void main(String[] args) throws IOException { /* * create a server * - * NOTE: https://docs.stackit.cloud/stackit/en/virtual-machine-flavors-75137231.html - * for available machine types + * NOTE: see the following link for available machine types + * https://docs.stackit.cloud/stackit/en/virtual-machine-flavors-75137231.html + * * */ Server newServer = iaasApi.createServer( From c1f886228ff9c745a5dffd8817ac13b019668bf4 Mon Sep 17 00:00:00 2001 From: Benjosh95 Date: Thu, 9 Oct 2025 19:50:19 +0200 Subject: [PATCH 16/28] fix pmd systemprintln, guardlogstatement --- .../authentication/examples/AuthenticationExample.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java b/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java index 8193377..b325913 100644 --- a/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java +++ b/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java @@ -57,7 +57,9 @@ public static void main(String[] args) { serviceAccountKeyContent.append(myReader.nextLine()); } } catch (FileNotFoundException e) { - System.err.println("File not found: " + serviceAccountKeyPath); + if (LOGGER.isLoggable(Level.SEVERE)) { + LOGGER.severe("File not found: " + serviceAccountKeyPath); + } return; } @@ -70,7 +72,9 @@ public static void main(String[] args) { privateKeyContent.append(myReader.nextLine()); } } catch (FileNotFoundException e) { - System.err.println("File not found: " + privateKeyPath); + if (LOGGER.isLoggable(Level.SEVERE)) { + LOGGER.severe("File not found: " + privateKeyPath); + } return; } From 071954b51ad746866dee6c5529554e6ccc087100 Mon Sep 17 00:00:00 2001 From: Benjosh95 Date: Thu, 9 Oct 2025 19:57:14 +0200 Subject: [PATCH 17/28] fix pmd AvoidThrowingRawExceptionTypes --- .../sdk/authentication/examples/AuthenticationExample.java | 6 +++--- .../customhttpclient/examples/CustomHttpClientExample.java | 2 +- .../java/cloud/stackit/sdk/iaas/examples/IaaSExample.java | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java b/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java index b325913..cf501a3 100644 --- a/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java +++ b/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java @@ -37,7 +37,7 @@ public static void main(String[] args) { LOGGER.info(response.toString()); } } catch (ApiException | IOException e) { - throw new RuntimeException(e); + throw new IllegalStateException(e); } /* @@ -97,7 +97,7 @@ public static void main(String[] args) { LOGGER.info(response.toString()); } } catch (ApiException | IOException e) { - throw new RuntimeException(e); + throw new IllegalStateException(e); } /* @@ -136,7 +136,7 @@ public static void main(String[] args) { LOGGER.info(response.toString()); } } catch (ApiException | IOException e) { - throw new RuntimeException(e); + throw new IllegalStateException(e); } } diff --git a/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java b/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java index 626796a..a6d7c8b 100644 --- a/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java +++ b/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java @@ -56,7 +56,7 @@ public static void main(String[] args) throws IOException { } } } catch (ApiException e) { - throw new RuntimeException(e); + throw new IllegalStateException(e); } } } diff --git a/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java b/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java index 8987aac..050c35a 100644 --- a/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java +++ b/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java @@ -323,7 +323,7 @@ public static void main(String[] args) throws IOException { } } catch (ApiException | InterruptedException e) { - throw new RuntimeException(e); + throw new IllegalStateException(e); } } From 03f6849fa543118bcd7928c19e8cc811d6899711 Mon Sep 17 00:00:00 2001 From: Benjosh95 Date: Thu, 9 Oct 2025 20:00:30 +0200 Subject: [PATCH 18/28] fix pmd NPathComplexity --- .../sdk/authentication/examples/AuthenticationExample.java | 2 +- .../sdk/resourcemanager/examples/ResourcemanagerExample.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java b/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java index cf501a3..954e7f2 100644 --- a/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java +++ b/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java @@ -18,7 +18,7 @@ final class AuthenticationExample { private static final String PRIVATE_KEY_PATH = "/path/to/private_key.pem"; private static final String SERVICE_ACCOUNT_MAIL = "name-1234@sa.stackit.cloud"; - @SuppressWarnings("PMD.CyclomaticComplexity") + @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) public static void main(String[] args) { /* OPTION 1: setting the paths to service account key (and private key) as configuration */ try { diff --git a/examples/resourcemanager/src/main/java/cloud/stackit/sdk/resourcemanager/examples/ResourcemanagerExample.java b/examples/resourcemanager/src/main/java/cloud/stackit/sdk/resourcemanager/examples/ResourcemanagerExample.java index 57be3bf..47a4ee3 100644 --- a/examples/resourcemanager/src/main/java/cloud/stackit/sdk/resourcemanager/examples/ResourcemanagerExample.java +++ b/examples/resourcemanager/src/main/java/cloud/stackit/sdk/resourcemanager/examples/ResourcemanagerExample.java @@ -22,6 +22,7 @@ final class ResourcemanagerExample { private static final Logger LOGGER = Logger.getLogger(ResourcemanagerExample.class.getName()); + @SuppressWarnings("PMD.NPathComplexity") public static void main(String[] args) throws IOException { // Credentials are read from the credentialsFile in `~/.stackit/credentials.json` or the env // STACKIT_SERVICE_ACCOUNT_KEY_PATH / STACKIT_SERVICE_ACCOUNT_KEY From 0eaef38cdde8867eb3d0f0e138b3fb17476809e0 Mon Sep 17 00:00:00 2001 From: Benjosh95 Date: Thu, 9 Oct 2025 20:12:32 +0200 Subject: [PATCH 19/28] rework fix pmd systemprintln, guardlogstatement --- .../examples/AuthenticationExample.java | 25 +-- .../examples/CustomHttpClientExample.java | 14 +- .../sdk/iaas/examples/IaaSExample.java | 156 +++++++----------- .../examples/ResourcemanagerExample.java | 29 +--- 4 files changed, 79 insertions(+), 145 deletions(-) diff --git a/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java b/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java index 954e7f2..7ba5c35 100644 --- a/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java +++ b/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java @@ -8,17 +8,14 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.util.Scanner; -import java.util.logging.Level; -import java.util.logging.Logger; final class AuthenticationExample { - private static final Logger LOGGER = Logger.getLogger(AuthenticationExample.class.getName()); private static final String SERVICE_ACCOUNT_KEY_PATH = "/path/to/sa_key.json"; private static final String PRIVATE_KEY_PATH = "/path/to/private_key.pem"; private static final String SERVICE_ACCOUNT_MAIL = "name-1234@sa.stackit.cloud"; - @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) + @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity", "PMD.SystemPrintln"}) public static void main(String[] args) { /* OPTION 1: setting the paths to service account key (and private key) as configuration */ try { @@ -33,9 +30,7 @@ public static void main(String[] args) { ListOrganizationsResponse response = api.listOrganizations(null, SERVICE_ACCOUNT_MAIL, null, null, null); - if (LOGGER.isLoggable(Level.INFO)) { - LOGGER.info(response.toString()); - } + System.out.println(response.toString()); } catch (ApiException | IOException e) { throw new IllegalStateException(e); } @@ -57,9 +52,7 @@ public static void main(String[] args) { serviceAccountKeyContent.append(myReader.nextLine()); } } catch (FileNotFoundException e) { - if (LOGGER.isLoggable(Level.SEVERE)) { - LOGGER.severe("File not found: " + serviceAccountKeyPath); - } + System.err.println("File not found: " + serviceAccountKeyPath); return; } @@ -72,9 +65,7 @@ public static void main(String[] args) { privateKeyContent.append(myReader.nextLine()); } } catch (FileNotFoundException e) { - if (LOGGER.isLoggable(Level.SEVERE)) { - LOGGER.severe("File not found: " + privateKeyPath); - } + System.err.println("File not found: " + privateKeyPath); return; } @@ -93,9 +84,7 @@ public static void main(String[] args) { ListOrganizationsResponse response = api.listOrganizations(null, SERVICE_ACCOUNT_MAIL, null, null, null); - if (LOGGER.isLoggable(Level.INFO)) { - LOGGER.info(response.toString()); - } + System.out.println(response.toString()); } catch (ApiException | IOException e) { throw new IllegalStateException(e); } @@ -132,9 +121,7 @@ public static void main(String[] args) { ListOrganizationsResponse response = api.listOrganizations(null, SERVICE_ACCOUNT_MAIL, null, null, null); - if (LOGGER.isLoggable(Level.INFO)) { - LOGGER.info(response.toString()); - } + System.out.println(response.toString()); } catch (ApiException | IOException e) { throw new IllegalStateException(e); } diff --git a/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java b/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java index a6d7c8b..080f0bc 100644 --- a/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java +++ b/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java @@ -7,8 +7,6 @@ import cloud.stackit.sdk.iaas.model.*; import java.io.IOException; import java.util.UUID; -import java.util.logging.Level; -import java.util.logging.Logger; import okhttp3.OkHttpClient; /* @@ -24,8 +22,8 @@ * * */ public class CustomHttpClientExample { - private static final Logger LOGGER = Logger.getLogger(CustomHttpClientExample.class.getName()); + @SuppressWarnings("PMD.SystemPrintln") public static void main(String[] args) throws IOException { // Credentials are read from the credentialsFile in `~/.stackit/credentials.json` or the env // STACKIT_SERVICE_ACCOUNT_KEY_PATH / STACKIT_SERVICE_ACCOUNT_KEY @@ -41,7 +39,7 @@ public static void main(String[] args) throws IOException { // the id of your STACKIT project, read from env var for this example String projectIdString = System.getenv("STACKIT_PROJECT_ID"); if (projectIdString == null || projectIdString.isEmpty()) { - LOGGER.severe("Environment variable 'STACKIT_PROJECT_ID' not found."); + System.err.println("Environment variable 'STACKIT_PROJECT_ID' not found."); return; } UUID projectId = UUID.fromString(projectIdString); @@ -49,11 +47,9 @@ public static void main(String[] args) throws IOException { try { /* list all servers */ ServerListResponse servers = iaasApi.listServers(projectId, false, null); - if (LOGGER.isLoggable(Level.INFO)) { - LOGGER.info("\nAvailable servers: "); - for (Server server : servers.getItems()) { - LOGGER.info("* " + server.getId() + " | " + server.getName()); - } + System.out.println("\nAvailable servers: "); + for (Server server : servers.getItems()) { + System.out.println("* " + server.getId() + " | " + server.getName()); } } catch (ApiException e) { throw new IllegalStateException(e); diff --git a/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java b/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java index 050c35a..c53b231 100644 --- a/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java +++ b/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java @@ -9,17 +9,15 @@ import java.util.Objects; import java.util.UUID; import java.util.concurrent.TimeUnit; -import java.util.logging.Level; -import java.util.logging.Logger; final class IaaSExample { - private static final Logger LOGGER = Logger.getLogger(IaaSExample.class.getName()); @SuppressWarnings({ "PMD.CyclomaticComplexity", "PMD.CognitiveComplexity", "PMD.NPathComplexity", - "PMD.NcssCount" + "PMD.NcssCount", + "PMD.SystemPrintln" }) public static void main(String[] args) throws IOException { /* @@ -31,7 +29,7 @@ public static void main(String[] args) throws IOException { // the id of your STACKIT project, read from env var for this example String projectIdString = System.getenv("STACKIT_PROJECT_ID"); if (projectIdString == null || projectIdString.isEmpty()) { - LOGGER.severe("Environment variable 'STACKIT_PROJECT_ID' not found."); + System.err.println("Environment variable 'STACKIT_PROJECT_ID' not found."); return; } UUID projectId = UUID.fromString(projectIdString); @@ -70,22 +68,18 @@ public static void main(String[] args) throws IOException { /* fetch the network we just created */ Network fetchedNetwork = iaasApi.getNetwork(projectId, newNetwork.getNetworkId()); - if (LOGGER.isLoggable(Level.INFO)) { - LOGGER.info("\nFetched network: "); - LOGGER.info("* Network name: " + fetchedNetwork.getName()); - LOGGER.info("* Id: " + fetchedNetwork.getNetworkId()); - LOGGER.info("* DHCP: " + (Boolean.TRUE.equals(fetchedNetwork.getDhcp()) ? "YES" : "NO")); - LOGGER.info("* Gateway: " + fetchedNetwork.getGateway()); - LOGGER.info("* Public IP: " + fetchedNetwork.getPublicIp()); - } + System.out.println("\nFetched network: "); + System.out.println("* Network name: " + fetchedNetwork.getName()); + System.out.println("* Id: " + fetchedNetwork.getNetworkId()); + System.out.println("* DHCP: " + (Boolean.TRUE.equals(fetchedNetwork.getDhcp()) ? "YES" : "NO")); + System.out.println("* Gateway: " + fetchedNetwork.getGateway()); + System.out.println("* Public IP: " + fetchedNetwork.getPublicIp()); /* list all available networks in the project */ NetworkListResponse networks = iaasApi.listNetworks(projectId, null); - if (LOGGER.isLoggable(Level.INFO)) { - LOGGER.info("\nAvailable networks: "); - for (Network network : networks.getItems()) { - LOGGER.info("* " + network.getName()); - } + System.out.println("\nAvailable networks: "); + for (Network network : networks.getItems()) { + System.out.println("* " + network.getName()); } /* @@ -96,11 +90,9 @@ public static void main(String[] args) throws IOException { /* list all available images */ ImageListResponse images = iaasApi.listImages(projectId, false, null); - if (LOGGER.isLoggable(Level.INFO)) { - LOGGER.info("\nAvailable images: "); - for (Image image : images.getItems()) { - LOGGER.info(image.getId() + " | " + image.getName()); - } + System.out.println("\nAvailable images: "); + for (Image image : images.getItems()) { + System.out.println(image.getId() + " | " + image.getName()); } /* get an image */ @@ -110,14 +102,12 @@ public static void main(String[] args) throws IOException { .getId(); // we just use a random image id in our example assert imageId != null; Image fetchedImage = iaasApi.getImage(projectId, imageId); - if (LOGGER.isLoggable(Level.INFO)) { - LOGGER.info("\nFetched image:"); - LOGGER.info("* Image name: " + fetchedImage.getName()); - LOGGER.info("* Image id: " + fetchedImage.getId()); - LOGGER.info("* Checksum: " + fetchedImage.getChecksum()); - LOGGER.info("* Created at: " + fetchedImage.getCreatedAt()); - LOGGER.info("* Updated at: " + fetchedImage.getUpdatedAt()); - } + System.out.println("\nFetched image:"); + System.out.println("* Image name: " + fetchedImage.getName()); + System.out.println("* Image id: " + fetchedImage.getId()); + System.out.println("* Checksum: " + fetchedImage.getChecksum()); + System.out.println("* Created at: " + fetchedImage.getCreatedAt()); + System.out.println("* Updated at: " + fetchedImage.getUpdatedAt()); /* * /////////////////////////////////////////////////////// @@ -127,11 +117,9 @@ public static void main(String[] args) throws IOException { /* list all available keypairs */ KeyPairListResponse keypairs = iaasApi.listKeyPairs(null); - if (LOGGER.isLoggable(Level.INFO)) { - LOGGER.info("\nAvailable keypairs: "); - for (Keypair keypair : keypairs.getItems()) { - LOGGER.info("* " + keypair.getName()); - } + System.out.println("\nAvailable keypairs: "); + for (Keypair keypair : keypairs.getItems()) { + System.out.println("* " + keypair.getName()); } /* create a keypair */ @@ -142,9 +130,7 @@ public static void main(String[] args) throws IOException { new CreateKeyPairPayload() .name("java-sdk-example-keypair-01") .publicKey(publicKey)); - if (LOGGER.isLoggable(Level.INFO)) { - LOGGER.info("\nKeypair created: " + newKeypair.getName()); - } + System.out.println("\nKeypair created: " + newKeypair.getName()); /* update the keypair */ assert newKeypair.getName() != null; @@ -155,15 +141,13 @@ public static void main(String[] args) throws IOException { /* fetch the keypair we just created / updated */ Keypair fetchedKeypair = iaasApi.getKeyPair(newKeypair.getName()); - if (LOGGER.isLoggable(Level.INFO)) { - LOGGER.info("\nFetched key pair: "); - LOGGER.info("* Name: " + fetchedKeypair.getName()); - if (fetchedKeypair.getLabels() != null) { - LOGGER.info("* Labels: " + fetchedKeypair.getLabels().toString()); // NOPMD GuardLogStatement - } - LOGGER.info("* Fingerprint: " + fetchedKeypair.getFingerprint()); - LOGGER.info("* Public key: " + fetchedKeypair.getPublicKey()); + System.out.println("\nFetched key pair: "); + System.out.println("* Name: " + fetchedKeypair.getName()); + if (fetchedKeypair.getLabels() != null) { + System.out.println("* Labels: " + fetchedKeypair.getLabels().toString()); } + System.out.println("* Fingerprint: " + fetchedKeypair.getFingerprint()); + System.out.println("* Public key: " + fetchedKeypair.getPublicKey()); /* * /////////////////////////////////////////////////////// @@ -173,25 +157,21 @@ public static void main(String[] args) throws IOException { /* list all available machine types */ MachineTypeListResponse machineTypes = iaasApi.listMachineTypes(projectId, null); - if (LOGGER.isLoggable(Level.INFO)) { - LOGGER.info("\nAvailable machine types: "); - for (MachineType machineType : machineTypes.getItems()) { - LOGGER.info("* " + machineType.getName()); - } + System.out.println("\nAvailable machine types: "); + for (MachineType machineType : machineTypes.getItems()) { + System.out.println("* " + machineType.getName()); } /* fetch details about a machine type */ MachineType fetchedMachineType = iaasApi.getMachineType(projectId, machineTypes.getItems().get(0).getName()); - if (LOGGER.isLoggable(Level.INFO)) { - LOGGER.info("\nFetched machine type: "); - LOGGER.info("* Machine type name: " + fetchedMachineType.getName()); - LOGGER.info("* Description: " + fetchedMachineType.getDescription()); - LOGGER.info("* Disk size: " + fetchedMachineType.getDisk()); - LOGGER.info("* RAM: " + fetchedMachineType.getRam()); - LOGGER.info("* vCPUs: " + fetchedMachineType.getVcpus()); - LOGGER.info("* Extra specs: " + fetchedMachineType.getExtraSpecs()); - } + System.out.println("\nFetched machine type: "); + System.out.println("* Machine type name: " + fetchedMachineType.getName()); + System.out.println("* Description: " + fetchedMachineType.getDescription()); + System.out.println("* Disk size: " + fetchedMachineType.getDisk()); + System.out.println("* RAM: " + fetchedMachineType.getRam()); + System.out.println("* vCPUs: " + fetchedMachineType.getVcpus()); + System.out.println("* Extra specs: " + fetchedMachineType.getExtraSpecs()); /* * create a server @@ -223,7 +203,7 @@ public static void main(String[] args) throws IOException { assert serverId != null; while (Objects.equals( iaasApi.getServer(projectId, serverId, false).getStatus(), "CREATING")) { - LOGGER.info("Waiting for server creation to complete ..."); + System.out.println("Waiting for server creation to complete ..."); TimeUnit.SECONDS.sleep(5); } @@ -236,36 +216,30 @@ public static void main(String[] args) throws IOException { /* list all servers */ ServerListResponse servers = iaasApi.listServers(projectId, false, null); - if (LOGGER.isLoggable(Level.INFO)) { - LOGGER.info("\nAvailable servers: "); - for (Server server : servers.getItems()) { - LOGGER.info("* " + server.getId() + " | " + server.getName()); - } + System.out.println("\nAvailable servers: "); + for (Server server : servers.getItems()) { + System.out.println("* " + server.getId() + " | " + server.getName()); } /* fetch the server we just created */ Server fetchedServer = iaasApi.getServer(projectId, serverId, false); - if (LOGGER.isLoggable(Level.INFO)) { - LOGGER.info("\nFetched server:"); - LOGGER.info("* Name: " + fetchedServer.getName()); - LOGGER.info("* Id: " + fetchedServer.getId()); - if (fetchedServer.getLabels() != null) { - LOGGER.info("* Labels: " + fetchedServer.getLabels().toString()); // NOPMD GuardLogStatement - } - LOGGER.info("* Machine type: " + fetchedServer.getMachineType()); - LOGGER.info("* Created at: " + fetchedServer.getCreatedAt()); - LOGGER.info("* Updated at: " + fetchedServer.getUpdatedAt()); - LOGGER.info("* Launched at: " + fetchedServer.getLaunchedAt()); + System.out.println("\nFetched server:"); + System.out.println("* Name: " + fetchedServer.getName()); + System.out.println("* Id: " + fetchedServer.getId()); + if (fetchedServer.getLabels() != null) { + System.out.println("* Labels: " + fetchedServer.getLabels().toString()); } + System.out.println("* Machine type: " + fetchedServer.getMachineType()); + System.out.println("* Created at: " + fetchedServer.getCreatedAt()); + System.out.println("* Updated at: " + fetchedServer.getUpdatedAt()); + System.out.println("* Launched at: " + fetchedServer.getLaunchedAt()); /* stop the server we just created */ iaasApi.stopServer(projectId, serverId); /* wait for the server to stop */ while (!Objects.equals( iaasApi.getServer(projectId, serverId, false).getPowerStatus(), "STOPPED")) { - if (LOGGER.isLoggable(Level.INFO)) { - LOGGER.info("Waiting for server " + serverId + " to stop..."); - } + System.out.println("Waiting for server " + serverId + " to stop..."); TimeUnit.SECONDS.sleep(5); } @@ -274,9 +248,7 @@ public static void main(String[] args) throws IOException { /* wait for the server to boot */ while (!Objects.equals( iaasApi.getServer(projectId, serverId, false).getPowerStatus(), "RUNNING")) { - if (LOGGER.isLoggable(Level.INFO)) { - LOGGER.info("Waiting for server " + serverId + " to boot..."); - } + System.out.println("Waiting for server " + serverId + " to boot..."); TimeUnit.SECONDS.sleep(5); } @@ -291,17 +263,13 @@ public static void main(String[] args) throws IOException { /* delete the server we just created */ iaasApi.deleteServer(projectId, serverId); - if (LOGGER.isLoggable(Level.INFO)) { - LOGGER.info("Deleted server: " + serverId); - } + System.out.println("Deleted server: " + serverId); /* wait for server deletion to complete */ while (true) { try { iaasApi.getServer(projectId, serverId, false); - if (LOGGER.isLoggable(Level.INFO)) { - LOGGER.info("Waiting for server deletion to complete..."); - } + System.out.println("Waiting for server deletion to complete..."); TimeUnit.SECONDS.sleep(5); } catch (ApiException e) { if (e.getCode() == HttpURLConnection.HTTP_NOT_FOUND) { @@ -312,15 +280,11 @@ public static void main(String[] args) throws IOException { /* delete the keypair we just created */ iaasApi.deleteKeyPair(newKeypair.getName()); - if (LOGGER.isLoggable(Level.INFO)) { - LOGGER.info("Deleted key pair: " + newKeypair.getName()); - } + System.out.println("Deleted key pair: " + newKeypair.getName()); /* delete the network we just created */ iaasApi.deleteNetwork(projectId, newNetwork.getNetworkId()); - if (LOGGER.isLoggable(Level.INFO)) { - LOGGER.info("Deleted network: " + newNetwork.getNetworkId()); - } + System.out.println("Deleted network: " + newNetwork.getNetworkId()); } catch (ApiException | InterruptedException e) { throw new IllegalStateException(e); diff --git a/examples/resourcemanager/src/main/java/cloud/stackit/sdk/resourcemanager/examples/ResourcemanagerExample.java b/examples/resourcemanager/src/main/java/cloud/stackit/sdk/resourcemanager/examples/ResourcemanagerExample.java index 47a4ee3..8222d78 100644 --- a/examples/resourcemanager/src/main/java/cloud/stackit/sdk/resourcemanager/examples/ResourcemanagerExample.java +++ b/examples/resourcemanager/src/main/java/cloud/stackit/sdk/resourcemanager/examples/ResourcemanagerExample.java @@ -16,13 +16,10 @@ import java.util.Arrays; import java.util.Collections; import java.util.UUID; -import java.util.logging.Level; -import java.util.logging.Logger; final class ResourcemanagerExample { - private static final Logger LOGGER = Logger.getLogger(ResourcemanagerExample.class.getName()); - @SuppressWarnings("PMD.NPathComplexity") + @SuppressWarnings({"PMD.NPathComplexity", "PMD.SystemPrintln"}) public static void main(String[] args) throws IOException { // Credentials are read from the credentialsFile in `~/.stackit/credentials.json` or the env // STACKIT_SERVICE_ACCOUNT_KEY_PATH / STACKIT_SERVICE_ACCOUNT_KEY @@ -32,11 +29,11 @@ public static void main(String[] args) throws IOException { String organizationIdString = System.getenv("STACKIT_ORGANIZATION_ID"); String memberSubjectString = System.getenv("STACKIT_MEMBER_SUBJECT"); if (organizationIdString == null || organizationIdString.isEmpty()) { - LOGGER.severe("Environment variable 'STACKIT_ORGANIZATION_ID' not found."); + System.err.println("Environment variable 'STACKIT_ORGANIZATION_ID' not found."); return; } if (memberSubjectString == null || memberSubjectString.isEmpty()) { - LOGGER.severe("Environment variable 'STACKIT_MEMBER_SUBJECT' not found."); + System.err.println("Environment variable 'STACKIT_MEMBER_SUBJECT' not found."); return; } UUID containerParentId = UUID.fromString(organizationIdString); @@ -57,17 +54,13 @@ public static void main(String[] args) throws IOException { .labels( Collections.singletonMap( "some-project-label", "foo-bar"))); - if (LOGGER.isLoggable(Level.INFO)) { - LOGGER.info("Project:\n" + project.toString()); - } + System.out.println("Project:\n" + project.toString()); /* list projects */ ListProjectsResponse responseListProject = resourceManagerApi.listProjects( organizationIdString, null, null, null, null, null); - if (LOGGER.isLoggable(Level.INFO)) { - LOGGER.info("Project List:\n" + responseListProject.toString()); - } + System.out.println("Project List:\n" + responseListProject.toString()); /* create a folder */ FolderResponse folder = @@ -76,17 +69,13 @@ public static void main(String[] args) throws IOException { .containerParentId(containerParentId.toString()) .name("java-testing-folder") .labels(Collections.singletonMap("foo", "bar"))); - if (LOGGER.isLoggable(Level.INFO)) { - LOGGER.info("Folder: \n" + folder.toString()); - } + System.out.println("Folder: \n" + folder.toString()); /* list folders */ ListFoldersResponse responseListFolders = resourceManagerApi.listFolders( organizationIdString, null, null, null, null, null); - if (LOGGER.isLoggable(Level.INFO)) { - LOGGER.info("Folder List:\n" + responseListFolders.toString()); - } + System.out.println("Folder List:\n" + responseListFolders.toString()); /* delete a project label */ resourceManagerApi.deleteProjectLabels(project.getContainerId(), Arrays.asList("foo")); @@ -108,9 +97,7 @@ public static void main(String[] args) throws IOException { /* get organization details */ OrganizationResponse organizationResponse = resourceManagerApi.getOrganization(organizationIdString); - if (LOGGER.isLoggable(Level.INFO)) { - LOGGER.info("Organization List:\n" + organizationResponse.toString()); - } + System.out.println("Organization List:\n" + organizationResponse.toString()); /* since you cannot delete a folder when a project is present we need to move the project out again */ resourceManagerApi.partialUpdateProject( From 53176a3f0b5a0a0bccfaece645c723d38253d0a4 Mon Sep 17 00:00:00 2001 From: Benjosh95 Date: Thu, 9 Oct 2025 20:15:21 +0200 Subject: [PATCH 20/28] fix pmd AvoidThrowingRawExceptionTypes --- .../sdk/resourcemanager/examples/ResourcemanagerExample.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/resourcemanager/src/main/java/cloud/stackit/sdk/resourcemanager/examples/ResourcemanagerExample.java b/examples/resourcemanager/src/main/java/cloud/stackit/sdk/resourcemanager/examples/ResourcemanagerExample.java index 8222d78..3102a17 100644 --- a/examples/resourcemanager/src/main/java/cloud/stackit/sdk/resourcemanager/examples/ResourcemanagerExample.java +++ b/examples/resourcemanager/src/main/java/cloud/stackit/sdk/resourcemanager/examples/ResourcemanagerExample.java @@ -110,7 +110,7 @@ public static void main(String[] args) throws IOException { /* delete folder */ resourceManagerApi.deleteFolder(folder.getContainerId(), true); } catch (ApiException e) { - throw new RuntimeException(e); + throw new IllegalStateException(e); } } From 10a066260f36f7c466bbc6e0c2ab98a5d9131690 Mon Sep 17 00:00:00 2001 From: Benjosh95 Date: Thu, 9 Oct 2025 20:21:23 +0200 Subject: [PATCH 21/28] fix pmd UseUtilityClass --- .../sdk/customhttpclient/examples/CustomHttpClientExample.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java b/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java index 080f0bc..dfaf883 100644 --- a/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java +++ b/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java @@ -21,7 +21,7 @@ * for everything to take advantage of the shared connection pool and to prevent resource leaks. * * */ -public class CustomHttpClientExample { +final class CustomHttpClientExample { @SuppressWarnings("PMD.SystemPrintln") public static void main(String[] args) throws IOException { From a9cc5bc22b0a419f3aa67e501a41a180fb7d09df Mon Sep 17 00:00:00 2001 From: Benjosh95 Date: Thu, 9 Oct 2025 20:31:18 +0200 Subject: [PATCH 22/28] fix pmd useutilityclass, refactor example class modifiers --- .../sdk/authentication/examples/AuthenticationExample.java | 6 ++---- .../customhttpclient/examples/CustomHttpClientExample.java | 2 +- .../java/cloud/stackit/sdk/iaas/examples/IaaSExample.java | 5 ++--- .../resourcemanager/examples/ResourcemanagerExample.java | 4 +--- 4 files changed, 6 insertions(+), 11 deletions(-) diff --git a/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java b/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java index 7ba5c35..ecda4c2 100644 --- a/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java +++ b/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java @@ -15,8 +15,8 @@ final class AuthenticationExample { private static final String PRIVATE_KEY_PATH = "/path/to/private_key.pem"; private static final String SERVICE_ACCOUNT_MAIL = "name-1234@sa.stackit.cloud"; - @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity", "PMD.SystemPrintln"}) - public static void main(String[] args) { + @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity", "PMD.SystemPrintln", "PMD.UseUtilityClass"}) + public static void main(String[] args) throws IOException { /* OPTION 1: setting the paths to service account key (and private key) as configuration */ try { ResourceManagerApi api = @@ -126,6 +126,4 @@ public static void main(String[] args) { throw new IllegalStateException(e); } } - - private AuthenticationExample() {} } diff --git a/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java b/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java index dfaf883..3a5cea8 100644 --- a/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java +++ b/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java @@ -23,7 +23,7 @@ * */ final class CustomHttpClientExample { - @SuppressWarnings("PMD.SystemPrintln") + @SuppressWarnings({"PMD.SystemPrintln", "PMD.UseUtilityClass"}) public static void main(String[] args) throws IOException { // Credentials are read from the credentialsFile in `~/.stackit/credentials.json` or the env // STACKIT_SERVICE_ACCOUNT_KEY_PATH / STACKIT_SERVICE_ACCOUNT_KEY diff --git a/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java b/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java index c53b231..8f7f143 100644 --- a/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java +++ b/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java @@ -17,7 +17,8 @@ final class IaaSExample { "PMD.CognitiveComplexity", "PMD.NPathComplexity", "PMD.NcssCount", - "PMD.SystemPrintln" + "PMD.SystemPrintln", + "PMD.UseUtilityClass" }) public static void main(String[] args) throws IOException { /* @@ -290,6 +291,4 @@ public static void main(String[] args) throws IOException { throw new IllegalStateException(e); } } - - private IaaSExample() {} } diff --git a/examples/resourcemanager/src/main/java/cloud/stackit/sdk/resourcemanager/examples/ResourcemanagerExample.java b/examples/resourcemanager/src/main/java/cloud/stackit/sdk/resourcemanager/examples/ResourcemanagerExample.java index 3102a17..41d9929 100644 --- a/examples/resourcemanager/src/main/java/cloud/stackit/sdk/resourcemanager/examples/ResourcemanagerExample.java +++ b/examples/resourcemanager/src/main/java/cloud/stackit/sdk/resourcemanager/examples/ResourcemanagerExample.java @@ -19,7 +19,7 @@ final class ResourcemanagerExample { - @SuppressWarnings({"PMD.NPathComplexity", "PMD.SystemPrintln"}) + @SuppressWarnings({"PMD.NPathComplexity", "PMD.SystemPrintln", "PMD.UseUtilityClass"}) public static void main(String[] args) throws IOException { // Credentials are read from the credentialsFile in `~/.stackit/credentials.json` or the env // STACKIT_SERVICE_ACCOUNT_KEY_PATH / STACKIT_SERVICE_ACCOUNT_KEY @@ -113,6 +113,4 @@ public static void main(String[] args) throws IOException { throw new IllegalStateException(e); } } - - private ResourcemanagerExample() {} } From 8330da9ffec491e9fd987fca0e7d70865e7acf27 Mon Sep 17 00:00:00 2001 From: Benjosh95 Date: Thu, 9 Oct 2025 20:33:56 +0200 Subject: [PATCH 23/28] fix pms useutilityclass classlevel --- .../sdk/authentication/examples/AuthenticationExample.java | 3 ++- .../customhttpclient/examples/CustomHttpClientExample.java | 3 ++- .../java/cloud/stackit/sdk/iaas/examples/IaaSExample.java | 4 ++-- .../sdk/resourcemanager/examples/ResourcemanagerExample.java | 3 ++- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java b/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java index ecda4c2..224edba 100644 --- a/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java +++ b/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java @@ -9,13 +9,14 @@ import java.io.IOException; import java.util.Scanner; +@SuppressWarnings("PMD.UseUtilityClass") final class AuthenticationExample { private static final String SERVICE_ACCOUNT_KEY_PATH = "/path/to/sa_key.json"; private static final String PRIVATE_KEY_PATH = "/path/to/private_key.pem"; private static final String SERVICE_ACCOUNT_MAIL = "name-1234@sa.stackit.cloud"; - @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity", "PMD.SystemPrintln", "PMD.UseUtilityClass"}) + @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity", "PMD.SystemPrintln"}) public static void main(String[] args) throws IOException { /* OPTION 1: setting the paths to service account key (and private key) as configuration */ try { diff --git a/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java b/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java index 3a5cea8..8165c21 100644 --- a/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java +++ b/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java @@ -21,9 +21,10 @@ * for everything to take advantage of the shared connection pool and to prevent resource leaks. * * */ +@SuppressWarnings("PMD.UseUtilityClass") final class CustomHttpClientExample { - @SuppressWarnings({"PMD.SystemPrintln", "PMD.UseUtilityClass"}) + @SuppressWarnings("PMD.SystemPrintln") public static void main(String[] args) throws IOException { // Credentials are read from the credentialsFile in `~/.stackit/credentials.json` or the env // STACKIT_SERVICE_ACCOUNT_KEY_PATH / STACKIT_SERVICE_ACCOUNT_KEY diff --git a/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java b/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java index 8f7f143..6d0bb55 100644 --- a/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java +++ b/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java @@ -10,6 +10,7 @@ import java.util.UUID; import java.util.concurrent.TimeUnit; +@SuppressWarnings("PMD.UseUtilityClass") final class IaaSExample { @SuppressWarnings({ @@ -17,8 +18,7 @@ final class IaaSExample { "PMD.CognitiveComplexity", "PMD.NPathComplexity", "PMD.NcssCount", - "PMD.SystemPrintln", - "PMD.UseUtilityClass" + "PMD.SystemPrintln" }) public static void main(String[] args) throws IOException { /* diff --git a/examples/resourcemanager/src/main/java/cloud/stackit/sdk/resourcemanager/examples/ResourcemanagerExample.java b/examples/resourcemanager/src/main/java/cloud/stackit/sdk/resourcemanager/examples/ResourcemanagerExample.java index 41d9929..00b01a6 100644 --- a/examples/resourcemanager/src/main/java/cloud/stackit/sdk/resourcemanager/examples/ResourcemanagerExample.java +++ b/examples/resourcemanager/src/main/java/cloud/stackit/sdk/resourcemanager/examples/ResourcemanagerExample.java @@ -17,9 +17,10 @@ import java.util.Collections; import java.util.UUID; +@SuppressWarnings("PMD.UseUtilityClass") final class ResourcemanagerExample { - @SuppressWarnings({"PMD.NPathComplexity", "PMD.SystemPrintln", "PMD.UseUtilityClass"}) + @SuppressWarnings({"PMD.NPathComplexity", "PMD.SystemPrintln"}) public static void main(String[] args) throws IOException { // Credentials are read from the credentialsFile in `~/.stackit/credentials.json` or the env // STACKIT_SERVICE_ACCOUNT_KEY_PATH / STACKIT_SERVICE_ACCOUNT_KEY From 75ccc2740e559fc8396ada5c65672168a3e69207 Mon Sep 17 00:00:00 2001 From: Benjosh95 Date: Thu, 9 Oct 2025 20:35:25 +0200 Subject: [PATCH 24/28] apply make fmt --- .../cloud/stackit/sdk/core/KeyFlowAuthenticator.java | 9 +++------ .../main/java/cloud/stackit/sdk/core/auth/SetupAuth.java | 6 ++---- .../authentication/examples/AuthenticationExample.java | 4 ++-- .../examples/CustomHttpClientExample.java | 2 +- .../cloud/stackit/sdk/iaas/examples/IaaSExample.java | 7 ++++--- 5 files changed, 12 insertions(+), 16 deletions(-) diff --git a/core/src/main/java/cloud/stackit/sdk/core/KeyFlowAuthenticator.java b/core/src/main/java/cloud/stackit/sdk/core/KeyFlowAuthenticator.java index aaf44c8..3315067 100644 --- a/core/src/main/java/cloud/stackit/sdk/core/KeyFlowAuthenticator.java +++ b/core/src/main/java/cloud/stackit/sdk/core/KeyFlowAuthenticator.java @@ -209,8 +209,7 @@ public String getAccessToken() throws IOException, ApiException, InvalidKeySpecE * @throws JsonSyntaxException parsing of the created access token failed */ @SuppressWarnings("PMD.AvoidSynchronizedStatement") - protected void createAccessToken() - throws InvalidKeySpecException, IOException, ApiException { + protected void createAccessToken() throws InvalidKeySpecException, IOException, ApiException { synchronized (tokenRefreshMonitor) { String assertion; try { @@ -236,8 +235,7 @@ protected void createAccessToken() * @throws JsonSyntaxException can not parse new access token */ @SuppressWarnings("PMD.AvoidSynchronizedStatement") - protected void createAccessTokenWithRefreshToken() - throws IOException, ApiException { + protected void createAccessTokenWithRefreshToken() throws IOException, ApiException { synchronized (tokenRefreshMonitor) { String refreshToken = token.refreshToken; try (Response response = requestToken(REFRESH_TOKEN, refreshToken).execute()) { @@ -253,8 +251,7 @@ protected void createAccessTokenWithRefreshToken() * @throws ApiException if the response has a bad status code * @throws JsonSyntaxException if the response body cannot be parsed */ - private void parseTokenResponse(Response response) - throws ApiException { + private void parseTokenResponse(Response response) throws ApiException { if (response.code() != HttpURLConnection.HTTP_OK) { String body = null; if (response.body() != null) { diff --git a/core/src/main/java/cloud/stackit/sdk/core/auth/SetupAuth.java b/core/src/main/java/cloud/stackit/sdk/core/auth/SetupAuth.java index 9ecde65..0dec702 100644 --- a/core/src/main/java/cloud/stackit/sdk/core/auth/SetupAuth.java +++ b/core/src/main/java/cloud/stackit/sdk/core/auth/SetupAuth.java @@ -126,8 +126,7 @@ private static String getDefaultCredentialsFilePath() { * can be found * @throws IOException thrown when a file can not be found */ - public static ServiceAccountKey setupKeyFlow(CoreConfiguration cfg) - throws IOException { + public static ServiceAccountKey setupKeyFlow(CoreConfiguration cfg) throws IOException { return setupKeyFlow(cfg, new EnvironmentVariables()); } @@ -304,8 +303,7 @@ private static String getPrivateKey(CoreConfiguration cfg, EnvironmentVariables * pathKey can not be found */ protected static String readValueFromCredentialsFile( - String path, String valueKey, String pathKey) - throws IOException { + String path, String valueKey, String pathKey) throws IOException { // Read credentials file String fileContent = new String(Files.readAllBytes(Paths.get(path)), StandardCharsets.UTF_8); diff --git a/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java b/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java index 224edba..93cc112 100644 --- a/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java +++ b/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java @@ -41,8 +41,8 @@ public static void main(String[] args) throws IOException { * * */ - /* read key content from a file, in production you can also read it - * e.g. from STACKIT secrets manager, so it's only kept in-memory + /* read key content from a file, in production you can also read it + * e.g. from STACKIT secrets manager, so it's only kept in-memory * */ String serviceAccountKeyPath = // replace it with the path to your service account key "examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/dummy_credentials/dummy-service-account-key.json"; diff --git a/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java b/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java index 8165c21..7582ddf 100644 --- a/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java +++ b/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java @@ -17,7 +17,7 @@ * NOTE: Passing the http client is optional, see our other examples * where no OkHttpClient object is passed. * In this case the STACKIT SDK ApiClients will just create their own OkHttpClient objects. - * Nevertheless, for production usage try to use one single OkHttpClient object + * Nevertheless, for production usage try to use one single OkHttpClient object * for everything to take advantage of the shared connection pool and to prevent resource leaks. * * */ diff --git a/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java b/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java index 6d0bb55..9107188 100644 --- a/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java +++ b/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java @@ -72,7 +72,8 @@ public static void main(String[] args) throws IOException { System.out.println("\nFetched network: "); System.out.println("* Network name: " + fetchedNetwork.getName()); System.out.println("* Id: " + fetchedNetwork.getNetworkId()); - System.out.println("* DHCP: " + (Boolean.TRUE.equals(fetchedNetwork.getDhcp()) ? "YES" : "NO")); + System.out.println( + "* DHCP: " + (Boolean.TRUE.equals(fetchedNetwork.getDhcp()) ? "YES" : "NO")); System.out.println("* Gateway: " + fetchedNetwork.getGateway()); System.out.println("* Public IP: " + fetchedNetwork.getPublicIp()); @@ -178,8 +179,8 @@ public static void main(String[] args) throws IOException { * create a server * * NOTE: see the following link for available machine types - * https://docs.stackit.cloud/stackit/en/virtual-machine-flavors-75137231.html - * + * https://docs.stackit.cloud/stackit/en/virtual-machine-flavors-75137231.html + * * */ Server newServer = iaasApi.createServer( From f4e40c87372c2b94e18aef8029a3ae114c0aef1c Mon Sep 17 00:00:00 2001 From: Benjosh95 Date: Thu, 9 Oct 2025 20:53:49 +0200 Subject: [PATCH 25/28] update ci pipeline to include new linter --- .github/workflows/ci.yaml | 3 +++ Makefile | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 40f50cc..01c5b17 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -27,6 +27,9 @@ jobs: - name: Check code format run: ./gradlew spotlessCheck + - name: Lint + run: make lint + - name: Test run: make test diff --git a/Makefile b/Makefile index 945cf42..686a63b 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ fmt: @./gradlew spotlessApply lint: - @echo "linting not ready yet" + @./gradlew pmdMain test: @./gradlew test From 245233d13779f5c7ee708df1839154fbe91a668c Mon Sep 17 00:00:00 2001 From: Benjosh95 Date: Tue, 14 Oct 2025 10:39:16 +0200 Subject: [PATCH 26/28] remove comments --- build.gradle | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/build.gradle b/build.gradle index d9f4fbe..07e2e25 100644 --- a/build.gradle +++ b/build.gradle @@ -71,21 +71,6 @@ allprojects { consoleOutput = true toolVersion = "7.12.0" - //rulesMinimumPriority = 5 - //ruleSets = [ - // "category/java/bestpractices.xml", - // "category/java/codestyle.xml", - // "category/java/design.xml", - // "category/java/documentation.xml", - // "category/java/errorprone.xml", - // "category/java/multithreading.xml", - // "category/java/performance.xml", - // "category/java/security.xml", - - // //"category/java/errorprone.xml", - // // "category/java/bestpractices.xml" - //] - // This tells PMD to use your custom ruleset file. ruleSetFiles = rootProject.files("config/pmd/pmd-ruleset.xml") From ddb2f6203a9903cc5fa2220e2ade43bd143f48db Mon Sep 17 00:00:00 2001 From: Benjosh95 Date: Tue, 14 Oct 2025 10:51:28 +0200 Subject: [PATCH 27/28] remove pmd utilityclass, add priv. constructors --- .../sdk/authentication/examples/AuthenticationExample.java | 3 ++- .../sdk/customhttpclient/examples/CustomHttpClientExample.java | 3 ++- .../main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java | 3 ++- .../sdk/resourcemanager/examples/ResourcemanagerExample.java | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java b/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java index 93cc112..8d0f49b 100644 --- a/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java +++ b/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java @@ -9,13 +9,14 @@ import java.io.IOException; import java.util.Scanner; -@SuppressWarnings("PMD.UseUtilityClass") final class AuthenticationExample { private static final String SERVICE_ACCOUNT_KEY_PATH = "/path/to/sa_key.json"; private static final String PRIVATE_KEY_PATH = "/path/to/private_key.pem"; private static final String SERVICE_ACCOUNT_MAIL = "name-1234@sa.stackit.cloud"; + private AuthenticationExample() {} + @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity", "PMD.SystemPrintln"}) public static void main(String[] args) throws IOException { /* OPTION 1: setting the paths to service account key (and private key) as configuration */ diff --git a/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java b/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java index 7582ddf..4e359e9 100644 --- a/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java +++ b/examples/custom-http-client/src/main/java/cloud/stackit/sdk/customhttpclient/examples/CustomHttpClientExample.java @@ -21,9 +21,10 @@ * for everything to take advantage of the shared connection pool and to prevent resource leaks. * * */ -@SuppressWarnings("PMD.UseUtilityClass") final class CustomHttpClientExample { + private CustomHttpClientExample() {} + @SuppressWarnings("PMD.SystemPrintln") public static void main(String[] args) throws IOException { // Credentials are read from the credentialsFile in `~/.stackit/credentials.json` or the env diff --git a/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java b/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java index 9107188..57f00fc 100644 --- a/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java +++ b/examples/iaas/src/main/java/cloud/stackit/sdk/iaas/examples/IaaSExample.java @@ -10,9 +10,10 @@ import java.util.UUID; import java.util.concurrent.TimeUnit; -@SuppressWarnings("PMD.UseUtilityClass") final class IaaSExample { + private IaaSExample() {} + @SuppressWarnings({ "PMD.CyclomaticComplexity", "PMD.CognitiveComplexity", diff --git a/examples/resourcemanager/src/main/java/cloud/stackit/sdk/resourcemanager/examples/ResourcemanagerExample.java b/examples/resourcemanager/src/main/java/cloud/stackit/sdk/resourcemanager/examples/ResourcemanagerExample.java index 00b01a6..b0899ee 100644 --- a/examples/resourcemanager/src/main/java/cloud/stackit/sdk/resourcemanager/examples/ResourcemanagerExample.java +++ b/examples/resourcemanager/src/main/java/cloud/stackit/sdk/resourcemanager/examples/ResourcemanagerExample.java @@ -17,8 +17,9 @@ import java.util.Collections; import java.util.UUID; -@SuppressWarnings("PMD.UseUtilityClass") final class ResourcemanagerExample { + + private ResourcemanagerExample() {} @SuppressWarnings({"PMD.NPathComplexity", "PMD.SystemPrintln"}) public static void main(String[] args) throws IOException { From 05d29e064cc6bd422170e1a0fff835f4f8ca8caf Mon Sep 17 00:00:00 2001 From: Benjosh95 Date: Tue, 14 Oct 2025 10:55:21 +0200 Subject: [PATCH 28/28] remove some pmd NPathComplexity --- .../sdk/authentication/examples/AuthenticationExample.java | 2 +- .../sdk/resourcemanager/examples/ResourcemanagerExample.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java b/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java index 8d0f49b..eb49083 100644 --- a/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java +++ b/examples/authentication/src/main/java/cloud/stackit/sdk/authentication/examples/AuthenticationExample.java @@ -17,7 +17,7 @@ final class AuthenticationExample { private AuthenticationExample() {} - @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity", "PMD.SystemPrintln"}) + @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.SystemPrintln"}) public static void main(String[] args) throws IOException { /* OPTION 1: setting the paths to service account key (and private key) as configuration */ try { diff --git a/examples/resourcemanager/src/main/java/cloud/stackit/sdk/resourcemanager/examples/ResourcemanagerExample.java b/examples/resourcemanager/src/main/java/cloud/stackit/sdk/resourcemanager/examples/ResourcemanagerExample.java index b0899ee..2e4ed5a 100644 --- a/examples/resourcemanager/src/main/java/cloud/stackit/sdk/resourcemanager/examples/ResourcemanagerExample.java +++ b/examples/resourcemanager/src/main/java/cloud/stackit/sdk/resourcemanager/examples/ResourcemanagerExample.java @@ -18,10 +18,10 @@ import java.util.UUID; final class ResourcemanagerExample { - + private ResourcemanagerExample() {} - @SuppressWarnings({"PMD.NPathComplexity", "PMD.SystemPrintln"}) + @SuppressWarnings({"PMD.SystemPrintln"}) public static void main(String[] args) throws IOException { // Credentials are read from the credentialsFile in `~/.stackit/credentials.json` or the env // STACKIT_SERVICE_ACCOUNT_KEY_PATH / STACKIT_SERVICE_ACCOUNT_KEY