Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ plugins {

java {
toolchain {
languageVersion = JavaLanguageVersion.of(25)
languageVersion = JavaLanguageVersion.of(21)
}
}

application {
mainClass = "com.shopping.inandout.routeservice.RouteServiceApplication"
mainClass = "com.shopping.inandout.routeservice.RouteService"
}

configurations {
Expand All @@ -31,17 +31,19 @@ repositories {
mavenLocal()
}

val smithyJavaVersion: String by project

dependencies {
implementation("software.amazon.smithy.java:client-core:0.0.3")
val smithyJavaVersion: String by project

implementation("software.amazon.smithy.java:core:$smithyJavaVersion")
implementation("software.amazon.smithy.java.codegen:plugins:$smithyJavaVersion")
// Core library for the Java client
// Adds the server implementation of the `RestJson1` protocol
implementation("software.amazon.smithy.java:aws-server-restjson:$smithyJavaVersion")
// Adds an HTTP server implementation based on netty
implementation("software.amazon.smithy.java:server-netty:$smithyJavaVersion")

compileOnly("org.projectlombok:lombok")
annotationProcessor("org.projectlombok:lombok")

implementation("org.springframework.boot:spring-boot-starter-jdbc")
implementation("org.springframework.boot:spring-boot-starter-r2dbc")
implementation("org.springframework.boot:spring-boot-starter-restclient")
Expand All @@ -52,9 +54,7 @@ dependencies {
implementation("org.springframework.boot:spring-boot-starter-webclient")
implementation("org.springframework.boot:spring-boot-starter-webmvc")
implementation("org.springframework.boot:spring-boot-starter-webservices")
compileOnly("org.projectlombok:lombok")
developmentOnly("org.springframework.boot:spring-boot-devtools")
annotationProcessor("org.projectlombok:lombok")
testImplementation("org.springframework.boot:spring-boot-starter-jdbc-test")
testImplementation("org.springframework.boot:spring-boot-starter-r2dbc-test")
testImplementation("org.springframework.boot:spring-boot-starter-restclient-test")
Expand All @@ -65,6 +65,7 @@ dependencies {
testImplementation("org.springframework.boot:spring-boot-starter-webclient-test")
testImplementation("org.springframework.boot:spring-boot-starter-webmvc-test")
testImplementation("org.springframework.boot:spring-boot-starter-webservices-test")

testRuntimeOnly("org.junit.platform:junit-platform-launcher")
testRuntimeOnly("com.h2database:h2")
testRuntimeOnly("io.r2dbc:r2dbc-h2")
Expand All @@ -73,7 +74,7 @@ dependencies {
afterEvaluate {
sourceSets {
main {
java.srcDir("build/java-client/java-client-codegen")
java.srcDir("build/java-route-service/java-server-codegen/com/shopping/inandout")
}
}
}
Expand All @@ -83,7 +84,7 @@ tasks.register<Exec>("smithyBuild") {
description = "Java models codegen from Smithy model."
commandLine("cmd", "/c", "smithy", "build",
"--config", ".\\InAndOut-API-Modelling\\smithy-build.json",
"--projection", "java-client",
"--projection", "java-route-service",
"--output", "build/")
}

Expand Down
49 changes: 49 additions & 0 deletions src/main/java/com/shopping/inandout/routeservice/RouteService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.shopping.inandout.routeservice;

import com.shopping.inandout.service.InAndOut;
import com.shopping.inandout.routeservice.activities.CreateRouteActivity;
import com.shopping.inandout.routeservice.activities.DeleteRouteActivity;
import com.shopping.inandout.routeservice.activities.GetRouteActivity;

import java.net.URI;
import java.util.logging.Logger;
import java.util.concurrent.ExecutionException;

import software.amazon.smithy.java.server.Service;
import software.amazon.smithy.java.server.Server;

public class RouteService implements Runnable {
private static final Logger LOGGER = Logger.getLogger(RouteService.class.getName());

public static void main(String... args) throws RuntimeException {
new RouteService().run();
}

@Override
public void run() {
Service service = InAndOut.builder()
.addCreateRouteOperation(new CreateRouteActivity())
.addDeleteRouteOperation(new DeleteRouteActivity())
.addGetRouteOperation(new GetRouteActivity())
.build();

Server server = Server.builder()
.endpoints(URI.create("http://localhost:8888"))
.addService(service)
.build();

LOGGER.info("Starting server...");
server.start();

try {
Thread.currentThread().join();
} catch (InterruptedException e) {

Check warning on line 40 in src/main/java/com/shopping/inandout/routeservice/RouteService.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Either re-interrupt this method or rethrow the "InterruptedException" that can be caught here.

See more on https://sonarcloud.io/project/issues?id=InAndOut-Stack_InAndOut-Backend&issues=AZ0BjerUqIRCOX4DAkrg&open=AZ0BjerUqIRCOX4DAkrg&pullRequest=9
LOGGER.info("Stopping server...");
try {
server.shutdown().get();
} catch (InterruptedException | ExecutionException ex) {

Check warning on line 44 in src/main/java/com/shopping/inandout/routeservice/RouteService.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Either re-interrupt this method or rethrow the "InterruptedException" that can be caught here.

See more on https://sonarcloud.io/project/issues?id=InAndOut-Stack_InAndOut-Backend&issues=AZ0BjerUqIRCOX4DAkrh&open=AZ0BjerUqIRCOX4DAkrh&pullRequest=9
throw new RuntimeException(ex);

Check warning on line 45 in src/main/java/com/shopping/inandout/routeservice/RouteService.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace generic exceptions with specific library exceptions or a custom exception.

See more on https://sonarcloud.io/project/issues?id=InAndOut-Stack_InAndOut-Backend&issues=AZ0BjerUqIRCOX4DAkrc&open=AZ0BjerUqIRCOX4DAkrc&pullRequest=9
}
}
Comment on lines +39 to +48
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

In Java, what happens when Thread.currentThread().join()is called from the current thread, and are JVM SIGINT/SIGTERM shutdowns delivered asInterruptedException on the main thread or through shutdown hooks?

💡 Result:

When Thread.currentThread.join is called from the current thread, the thread blocks indefinitely. The join method waits for the target thread to terminate by repeatedly checking isAlive and calling wait(0) on the thread's monitor while alive. Since the thread is waiting on its own monitor and cannot notify itself (as it's blocked), it deadlocks and never proceeds. This is a common idiom to prevent the main thread from exiting in server applications, allowing daemon threads to continue running until an external shutdown signal is received. JVM SIGINT (Ctrl+C) and SIGTERM shutdowns do not deliver InterruptedException to the main thread (or any application threads). These signals trigger the JVM's shutdown sequence: shutdown hooks are executed (if registered via Runtime.addShutdownHook), then the JVM halts. InterruptedException is only thrown due to explicit Thread.interrupt calls, not OS signals. The JVM handles SIGINT/SIGTERM internally without interrupting application threads; instead, it runs shutdown hooks for cleanup. Daemon threads continue during shutdown but are terminated when the JVM halts.

Citations:


🏁 Script executed:

fd -t f RouteService.java

Repository: InAndOut-Stack/InAndOut-Route-Service

Length of output: 147


🏁 Script executed:

cat -n src/main/java/com/shopping/inandout/routeservice/RouteService.java | sed -n '35,55p'

Repository: InAndOut-Stack/InAndOut-Route-Service

Length of output: 624


Thread.currentThread().join() will not trigger graceful shutdown on JVM termination.

Calling Thread.currentThread().join() blocks indefinitely and relies on InterruptedException to unblock. However, normal JVM shutdown signals (Ctrl+C, SIGTERM) do not interrupt application threads—they trigger shutdown hooks instead. This means server.shutdown().get() in the catch block will never execute during graceful shutdown, leaving server resources uncleaned.

Register a shutdown hook with Runtime.addShutdownHook() for graceful shutdown logic, and use a CountDownLatch or CompletableFuture to keep the main thread alive until shutdown is triggered. If catching InterruptedException, restore the interrupt flag before returning.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/shopping/inandout/routeservice/RouteService.java` around
lines 39 - 48, Replace the blocking Thread.currentThread().join() approach and
move the graceful shutdown logic into a Runtime.addShutdownHook so JVM signals
trigger server.shutdown().get(); keep the main thread waiting with a
CountDownLatch or CompletableFuture that the shutdown hook completes, and in any
InterruptedException handling (around join or waiting) restore the interrupt
flag (Thread.currentThread().interrupt()) before returning; update places
referencing Thread.currentThread().join(), the catch of InterruptedException,
LOGGER.info("Stopping server...") and server.shutdown().get() to use this
shutdown hook + latch/future pattern so resources are cleaned on JVM
termination.

}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.shopping.inandout.routeservice.activities;

import com.shopping.inandout.service.CreateRouteOperation;
import com.shopping.inandout.model.CreateRouteInput;
import com.shopping.inandout.model.CreateRouteOutput;

import software.amazon.smithy.java.server.RequestContext;

public class CreateRouteActivity implements CreateRouteOperation {
public CreateRouteOutput createRoute(CreateRouteInput input, RequestContext context) {
return CreateRouteOutput.builder().build();
Comment on lines +12 to +13
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

createRoute currently reports success without creating a route.

Line 13 ignores input and returns a blank CreateRouteOutput, so callers can get a successful create response even though nothing was persisted or delegated downstream. Please wire this handler to the real create path, or fail explicitly until that implementation exists.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/shopping/inandout/routeservice/activities/CreateRouteActivity.java`
around lines 12 - 13, The createRoute method in CreateRouteActivity currently
ignores the input and returns an empty CreateRouteOutput; update
CreateRouteActivity.createRoute to either call the real creation flow (e.g.,
delegate to your route persistence/service method such as
RouteService.createRoute or RouteRepository.save using the provided
CreateRouteInput and RequestContext) and return a populated CreateRouteOutput
reflecting the persisted route, or if the implementation isn’t ready, explicitly
fail by throwing a clear exception (e.g., UnsupportedOperationException) instead
of returning a success; ensure the method uses CreateRouteInput fields to build
the created resource and include any IDs or status in CreateRouteOutput.

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.shopping.inandout.routeservice.activities;

import com.shopping.inandout.service.DeleteRouteOperation;
import com.shopping.inandout.model.DeleteRouteInput;
import com.shopping.inandout.model.DeleteRouteOutput;

import software.amazon.smithy.java.server.RequestContext;

public class DeleteRouteActivity implements DeleteRouteOperation {
public DeleteRouteOutput deleteRoute(DeleteRouteInput input, RequestContext context) {
return DeleteRouteOutput.builder().build();
Comment on lines +10 to +11
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

deleteRoute acknowledges deletes without deleting anything.

Line 11 ignores the request and returns success unconditionally, so clients can believe a route was removed while the backing state remains untouched. This needs to call the real delete path, or fail explicitly until it exists.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/shopping/inandout/routeservice/activities/DeleteRouteActivity.java`
around lines 10 - 11, deleteRoute currently always returns success without doing
any deletion; update DeleteRouteActivity.deleteRoute to invoke the actual
deletion flow using the route identifier from DeleteRouteInput (e.g., call the
repository or service delete method such as RouteRepository.deleteById or
RouteService.deleteRoute), handle not-found cases by returning a
failure/exception instead of success, and surface errors/logging via the
provided RequestContext; ensure DeleteRouteOutput reflects the real outcome
(success only when delete succeeded).

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.shopping.inandout.routeservice.activities;

import com.shopping.inandout.service.GetRouteOperation;
import com.shopping.inandout.model.GetRouteInput;
import com.shopping.inandout.model.GetRouteOutput;

import software.amazon.smithy.java.server.RequestContext;

public class GetRouteActivity implements GetRouteOperation {
public GetRouteOutput getRoute(GetRouteInput input, RequestContext context) {
return GetRouteOutput.builder().build();
Comment on lines +10 to +11
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

getRoute always returns an empty payload.

Line 11 never uses input to look anything up, so every request will succeed with the same blank response regardless of the requested route. Please delegate to the actual lookup path, or return a modeled not-found/not-implemented error instead of a successful empty body.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/shopping/inandout/routeservice/activities/GetRouteActivity.java`
around lines 10 - 11, getRoute currently always returns an empty GetRouteOutput
regardless of input; update GetRouteActivity.getRoute to use the provided
GetRouteInput and RequestContext to perform the actual lookup (e.g., call your
route repository/service with input identifiers) and populate the GetRouteOutput
with the found route data, and if no route is found return or throw a modeled
not-found error (or a not-implemented error if lookup is not yet available)
instead of returning a successful empty body.

}
}