Skip to content

Commit 719be51

Browse files
committed
core: Added and updated enums, utilities, annotations, and validators
1 parent daa7c89 commit 719be51

19 files changed

Lines changed: 720 additions & 13 deletions

File tree

.github/workflows/auto-assign.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
name: Auto Assign
2+
on:
3+
issues:
4+
types: [opened, reopened]
5+
pull_request:
6+
types: [opened, reopened]
7+
jobs:
8+
run:
9+
runs-on: ubuntu-latest
10+
permissions:
11+
issues: write
12+
pull-requests: write
13+
steps:
14+
- name: 'Auto-assign issue'
15+
uses: pozil/auto-assign-issue@v2
16+
with:
17+
repo-token: ${{ secrets.GITHUB_TOKEN }}
18+
assignees: shortthirdman
19+
numOfAssignee: 1
20+
allowSelfAssign: true

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@
186186
same "printed page" as the copyright notice for easier
187187
identification within third-party archives.
188188

189-
Copyright [yyyy] [name of copyright owner]
189+
Copyright 2025 ShortThirdMan
190190

191191
Licensed under the Apache License, Version 2.0 (the "License");
192192
you may not use this file except in compliance with the License.

pom.xml

Lines changed: 85 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,24 @@
1111
<inceptionYear>2025</inceptionYear>
1212

1313
<properties>
14-
<java.version>1.8</java.version>
14+
<isCI>true</isCI>
15+
<github.repository>shortthirdman-org/PrimeKit</github.repository>
16+
<java.version>[11,24)</java.version>
1517
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
16-
<maven.compiler.source>1.8</maven.compiler.source>
17-
<maven.compiler.target>1.8</maven.compiler.target>
18+
<maven.compiler.source>${java.version}</maven.compiler.source>
19+
<maven.compiler.target>${java.version}</maven.compiler.target>
1820
<maven.compiler.release>21</maven.compiler.release>
1921
<lombok.version>1.18.32</lombok.version>
2022
<jjwt.version>0.12.6</jjwt.version>
2123
<springframework.version>6.2.5</springframework.version>
2224
<spring-data.version>3.2.5</spring-data.version>
23-
<fasterxml-jackson.version>2.15.4</fasterxml-jackson.version>
25+
<fasterxml-jackson.version>2.18.4</fasterxml-jackson.version>
2426
<jakarta.xml-bind.version>4.0.2</jakarta.xml-bind.version>
25-
<postgresql.version></postgresql.version>
27+
<postgresql.version>42.</postgresql.version>
2628
<hibernate.version>5.6.10.Final</hibernate.version>
27-
<junit.version>5.11.0</junit.version>
29+
<junit.version>5.12.0</junit.version>
30+
<resilience4j.version>2.3.0</resilience4j.version>
31+
<guava.version>32.1.3-jre</guava.version>
2832
<postgresql.version>42.7.3</postgresql.version>
2933
<junit-jupiter.version>5.10.2</junit-jupiter.version>
3034
<assertj.version>3.19.0</assertj.version>
@@ -158,6 +162,18 @@
158162
<artifactId>spring-data-commons</artifactId>
159163
<version>${spring-data.version}</version>
160164
</dependency>
165+
166+
<dependency>
167+
<groupId>io.github.resilience4j</groupId>
168+
<artifactId>resilience4j-circuitbreaker</artifactId>
169+
<version>${resilience4j.version}</version>
170+
<optional>true</optional>
171+
</dependency>
172+
<dependency>
173+
<groupId>com.google.guava</groupId>
174+
<artifactId>guava</artifactId>
175+
<version>${guava.version}</version>
176+
</dependency>
161177

162178
<dependency>
163179
<groupId>org.postgresql</groupId>
@@ -214,6 +230,11 @@
214230
<artifactId>jackson-annotations</artifactId>
215231
<version>${fasterxml-jackson.version}</version>
216232
</dependency>
233+
<dependency>
234+
<groupId>com.fasterxml.jackson.core</groupId>
235+
<artifactId>jackson-databind</artifactId>
236+
<version>${fasterxml-jackson.version}</version>
237+
</dependency>
217238

218239
<dependency>
219240
<groupId>org.apache.commons</groupId>
@@ -247,7 +268,7 @@
247268
<dependency>
248269
<groupId>org.junit.jupiter</groupId>
249270
<artifactId>junit-jupiter-engine</artifactId>
250-
<version>${junit-jupiter.version}</version>
271+
<!-- <version>${junit-jupiter.version}</version> -->
251272
<scope>test</scope>
252273
</dependency>
253274
<dependency>
@@ -266,8 +287,7 @@
266287

267288
<build>
268289
<finalName>primekit-essentials-${project.version}</finalName>
269-
<pluginManagement>
270-
<plugins>
290+
<plugins>
271291
<plugin>
272292
<artifactId>maven-resources-plugin</artifactId>
273293
<version>3.3.1</version>
@@ -280,14 +300,45 @@
280300
<encoding>UTF-8</encoding>
281301
<source>${java.version}</source>
282302
<target>${java.version}</target>
303+
<annotationProcessorPaths>
304+
<path>
305+
<groupId>org.projectlombok</groupId>
306+
<artifactId>lombok</artifactId>
307+
<version>${lombok.version}</version>
308+
</path>
309+
</annotationProcessorPaths>
283310
</configuration>
284311
</plugin>
285312
<plugin>
286313
<artifactId>maven-surefire-plugin</artifactId>
287314
<version>3.3.0</version>
288315
<configuration>
289316
<printSummary>true</printSummary>
317+
<forkCount>1</forkCount>
318+
<encoding>${project.build.sourceEncoding}</encoding>
319+
<reportFormat>brief</reportFormat>
320+
<testFailureIgnore>true</testFailureIgnore>
321+
<properties>
322+
<configurationParameters>
323+
junit.jupiter.conditions.deactivate = *
324+
junit.jupiter.extensions.autodetection.enabled = true
325+
junit.jupiter.testinstance.lifecycle.default = per_class
326+
junit.jupiter.execution.parallel.enabled = true
327+
</configurationParameters>
328+
</properties>
290329
</configuration>
330+
<dependencies>
331+
<dependency>
332+
<groupId>me.fabriciorby</groupId>
333+
<artifactId>maven-surefire-junit5-tree-reporter</artifactId>
334+
<version>1.2.1</version>
335+
</dependency>
336+
<dependency>
337+
<groupId>org.apache.maven.surefire</groupId>
338+
<artifactId>surefire-junit-platform</artifactId>
339+
<version>3.0.0</version>
340+
</dependency>
341+
</dependencies>
291342
</plugin>
292343
<plugin>
293344
<artifactId>maven-jar-plugin</artifactId>
@@ -301,16 +352,32 @@
301352
<artifactId>maven-deploy-plugin</artifactId>
302353
<version>3.1.2</version>
303354
</plugin>
355+
<plugin>
356+
<groupId>org.apache.maven.plugins</groupId>
357+
<artifactId>maven-failsafe-plugin</artifactId>
358+
<version>3.5.3</version>
359+
<configuration>
360+
<failIfNoSpecifiedTests>true</failIfNoSpecifiedTests>
361+
<testFailureIgnore>true</testFailureIgnore>
362+
</configuration>
363+
</plugin>
304364
<plugin>
305365
<groupId>org.apache.maven.plugins</groupId>
306366
<artifactId>maven-source-plugin</artifactId>
307367
<version>3.2.1</version>
368+
<configuration>
369+
<finalName>primekit-essentials-${project.version}</finalName>
370+
<attach>true</attach>
371+
<!-- <outputDirectory>${project.build.directory}/generated-sources</outputDirectory>-->
372+
<outputTimestamp>${build.timestamp}</outputTimestamp>
373+
</configuration>
308374
<executions>
309375
<execution>
310376
<id>attach-sources</id>
311377
<phase>install</phase>
312378
<goals>
313379
<goal>jar-no-fork</goal>
380+
<goal>test-jar-no-fork</goal>
314381
</goals>
315382
</execution>
316383
</executions>
@@ -338,18 +405,24 @@
338405
<id>GenerateGitChangelog</id>
339406
<phase>generate-sources</phase>
340407
<goals>
408+
<goal>semantic-version</goal>
341409
<goal>git-changelog</goal>
342410
</goals>
343411
<configuration>
344412
<templateFile>changelog.mustache</templateFile>
413+
<prependToFile>true</prependToFile>
345414
<readableTagName>-([^-]+?)$</readableTagName>
346415
<file>CHANGELOG.md</file>
347-
<mediaWiki>false</mediaWiki>
416+
<skip>${isCI}</skip>
417+
<!--<updatePomWithCurrentSemanticVersionSuffixSnapshot>false</updatePomWithCurrentSemanticVersionSuffixSnapshot>
418+
<updatePomWithCurrentSemanticVersionSuffixSnapshotIfNotTagged>true</updatePomWithCurrentSemanticVersionSuffixSnapshotIfNotTagged>
419+
<semanticMajorVersionPattern>^[Bb]reaking</semanticMajorVersionPattern>
420+
<semanticMinorVersionPattern>[Ff]eature</semanticMinorVersionPattern>
421+
<semanticPatchVersionPattern>[Ff]ix</semanticPatchVersionPattern>-->
348422
</configuration>
349423
</execution>
350424
</executions>
351425
</plugin>
352-
</plugins>
353-
</pluginManagement>
426+
</plugins>
354427
</build>
355428
</project>

src/main/java/com/shortthirdman/primekit/essentials/common/YearWeek.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package com.shortthirdman.primekit.essentials.common;
22

3+
import org.jetbrains.annotations.Contract;
4+
import org.jetbrains.annotations.NotNull;
5+
36
import java.text.MessageFormat;
47
import java.time.DateTimeException;
58
import java.time.LocalDate;
@@ -25,6 +28,8 @@ public static YearWeek from(TemporalAccessor temporal) {
2528
}
2629
}
2730

31+
@NotNull
32+
@Contract(pure = true)
2833
@Override
2934
public String toString() {
3035
return MessageFormat.format("{0}-{1}", year, week);
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.shortthirdman.primekit.essentials.common.enums;
2+
3+
import lombok.Getter;
4+
5+
@Getter
6+
public enum Directions {
7+
8+
EAST("East", "E"),
9+
NORTH("North", "N"),
10+
NORTH_EAST("North-East", "NE"),
11+
NORTH_WEST("North-West", "NW"),
12+
SOUTH("South", "S"),
13+
SOUTH_EAST("South-East", "SE"),
14+
SOUTH_WEST("South-West", "SW"),
15+
WEST("West", "SW");
16+
17+
private final String name;
18+
private final String symbol;
19+
20+
Directions(String name, String symbol) {
21+
this.name = name;
22+
this.symbol = symbol;
23+
}
24+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.shortthirdman.primekit.essentials.common.enums;
2+
3+
import lombok.Getter;
4+
5+
@Getter
6+
public enum Seasons {
7+
8+
WINTER("Winter"),
9+
SPRING("Spring"),
10+
SUMMER("Summer"),
11+
FALL("Fall"),
12+
AUTUMN("Autumn");
13+
14+
private final String name;
15+
16+
Seasons(String name) {
17+
this.name = name;
18+
}
19+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.shortthirdman.primekit.essentials.common.util;
2+
3+
import java.io.IOException;
4+
import java.net.URI;
5+
import java.net.http.HttpClient;
6+
import java.net.http.HttpRequest;
7+
import java.net.http.HttpResponse;
8+
9+
public final class HttpUtils {
10+
11+
private HttpUtils() {}
12+
13+
private static final HttpClient client = HttpClient.newBuilder()
14+
.version(HttpClient.Version.HTTP_2)
15+
.build();
16+
17+
public static String get(String url) throws IOException, InterruptedException {
18+
HttpRequest request = HttpRequest.newBuilder()
19+
.uri(URI.create(url))
20+
.GET()
21+
.build();
22+
return client.send(request, HttpResponse.BodyHandlers.ofString()).body();
23+
}
24+
25+
public static String post(String url, String jsonBody) throws IOException, InterruptedException {
26+
HttpRequest request = HttpRequest.newBuilder()
27+
.uri(URI.create(url))
28+
.header("Content-Type", "application/json")
29+
.POST(HttpRequest.BodyPublishers.ofString(jsonBody))
30+
.build();
31+
return client.send(request, HttpResponse.BodyHandlers.ofString()).body();
32+
}
33+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package com.shortthirdman.primekit.essentials.core;
2+
3+
import java.util.*;
4+
import java.util.concurrent.*;
5+
import java.util.function.Function;
6+
7+
public class AsyncRequestMerger<K, V> implements RequestMerger<K, V> {
8+
9+
private final ConcurrentHashMap<K, CompletableFuture<Optional<V>>> pendingRequests = new ConcurrentHashMap<>();
10+
private final List<K> keyQueue = Collections.synchronizedList(new ArrayList<>());
11+
private final Function<List<K>, Map<K, V>> batchFunction;
12+
private final long windowTimeMillis;
13+
private final int maxBatchSize;
14+
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
15+
private final ExecutorService batchExecutor = Executors.newFixedThreadPool(2);
16+
private final Semaphore backpressure = new Semaphore(5);
17+
18+
public AsyncRequestMerger(Function<List<K>, Map<K, V>> batchFunction, long windowTimeMillis, int maxBatchSize) {
19+
this.batchFunction = batchFunction;
20+
this.windowTimeMillis = windowTimeMillis;
21+
this.maxBatchSize = maxBatchSize;
22+
}
23+
24+
@Override
25+
public CompletableFuture<Optional<V>> get(K key) {
26+
CompletableFuture<Optional<V>> future = new CompletableFuture<>();
27+
CompletableFuture<Optional<V>> existingFuture = pendingRequests.putIfAbsent(key, future);
28+
if (existingFuture != null) {
29+
return existingFuture; // Return existing future if key is already queued
30+
}
31+
synchronized (keyQueue) {
32+
keyQueue.add(key);
33+
if (keyQueue.size() == 1) {
34+
scheduler.schedule(this::processBatch, windowTimeMillis, TimeUnit.MILLISECONDS);
35+
} else if (keyQueue.size() >= maxBatchSize) {
36+
processBatch();
37+
}
38+
}
39+
return future;
40+
}
41+
42+
private void processBatch() {
43+
List<K> batch;
44+
synchronized (keyQueue) {
45+
if (keyQueue.isEmpty()) return;
46+
batch = new ArrayList<>(keyQueue);
47+
keyQueue.clear();
48+
}
49+
try {
50+
backpressure.acquire();
51+
batchExecutor.submit(() -> {
52+
Map<K, V> results = null;
53+
try {
54+
results = batchFunction.apply(batch);
55+
for (K key : batch) {
56+
CompletableFuture<Optional<V>> future = pendingRequests.remove(key);
57+
if (future != null) {
58+
future.complete(Optional.ofNullable(results.get(key)));
59+
}
60+
}
61+
} catch (Exception e) {
62+
for (K key : batch) {
63+
CompletableFuture<Optional<V>> future = pendingRequests.remove(key);
64+
if (future != null) {
65+
future.completeExceptionally(e);
66+
}
67+
}
68+
} finally {
69+
backpressure.release();
70+
}
71+
});
72+
} catch (InterruptedException e) {
73+
Thread.currentThread().interrupt();
74+
}
75+
}
76+
77+
@Override
78+
public void shutdown() {
79+
scheduler.shutdown();
80+
batchExecutor.shutdown();
81+
}
82+
}

0 commit comments

Comments
 (0)