Skip to content

Commit 679fc8b

Browse files
slayerjainclaude
andcommitted
review: address Copilot review round 2 on sap-demo-java
Applies 17 fixes from #126 review: Alignment / correctness: - Dockerfile: amazoncorretto:25 -> 21 (match pom java.version=21) - docker-compose.yml, k8s/postgres.yaml: postgres:15-alpine -> 16-alpine (align with README/PR "Postgres 16") - kind-config.yaml: add extraPortMappings for 30080 so the NodePort Service is reachable at http://localhost:30080 (previously 80/443 only) - SapClientConfig: plumb readTimeoutSeconds through RestTemplateBuilder (HttpComponentsClientHttpRequestFactory.setReadTimeout was removed in Spring 6 / HttpClient5) + drop Javadoc reference to the never-implemented IdentityEncodingInterceptor Bugs / robustness: - TagController.remove: trim + lowercase before echoing "tag" in response, so the response matches the value used by the service - GlobalExceptionHandler.handleUnexpected: stop leaking ex.getMessage() to clients; log full exception server-side with correlationId + path, return a generic body that invites the caller to quote the correlationId - TagService.add: replace exists() + findAll().stream().filter().orElseThrow() with a single findByCustomerIdAndTag Optional lookup, eliminating the race window + the unsafe orElseThrow(); CustomerTagRepository gains the matching finder - Customer360AggregatorService: split the combined `catch (InterruptedException | ExecutionException)` so Thread.currentThread().interrupt() fires only for InterruptedException - deploy_kind.sh build_and_load: replace `[ src -nt target/...jar ]` (which only compares the src directory mtime) with a `find src pom.xml -newer` sweep so rebuilds actually trigger after any file change Test / housekeeping: - Customer360ApplicationTests: add @AutoConfigureTestDatabase(Replace.ANY) + H2 test dep so the context-load smoke test runs without a live Postgres; disable Flyway (migrations are Postgres-specific) and let Hibernate generate the schema from entities at test time. Verified: context loads in ~5.6s locally - application.yml: drop logging.pattern.console — logback-spring.xml owns the pattern (and overrides Boot's key when present); avoids drift - keploy.yml: typo "configration" -> "configuration" - README.md Quick start: drop absolute /home/shubham/... path, use repo-relative `cd sap-demo-java` Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 329d6a5 commit 679fc8b

16 files changed

Lines changed: 98 additions & 51 deletions

File tree

sap-demo-java/Dockerfile

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
# syntax=docker/dockerfile:1.7
22
#
3-
# Uses amazoncorretto:25 — Amazon Linux 2023-based, minimal, JDK-ready.
4-
# The jar is built outside Docker (mvn package); this image just packages it
5-
# and runs it. K8s securityContext enforces the non-root runtime UID (1001).
3+
# Uses amazoncorretto:21 — Amazon Linux 2023-based, minimal, JDK-ready.
4+
# Matches the Maven toolchain (pom.xml targets Java 21). The jar is built
5+
# outside Docker (mvn package); this image just packages it and runs it.
6+
# K8s securityContext enforces the non-root runtime UID (1001).
67
#
78
# Docker Hub pull rate limits are avoided by relying on the locally cached
8-
# amazoncorretto:25 image.
9+
# amazoncorretto:21 image.
910

10-
FROM amazoncorretto:25
11+
FROM amazoncorretto:21
1112

1213
WORKDIR /app
1314

sap-demo-java/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ Swagger UI inside the kind cluster: `http://localhost:30080/swagger-ui.html`.
8181
## Quick start (kind cluster)
8282

8383
```bash
84-
cd /home/shubham/tricentis/sap_testing/sap_demo_java
84+
cd sap-demo-java
8585

8686
# 1. One-time: drop your SAP API key into .env
8787
cp .env.example .env

sap-demo-java/deploy_kind.sh

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,18 @@ build_and_load() {
194194
fail "cluster '${CLUSTER_NAME}' does not exist — run '$0 -c ${CLUSTER_NAME} cluster' first"
195195
exit 1
196196
fi
197-
if [ ! -f target/customer360.jar ] || [ src -nt target/customer360.jar ]; then
197+
# Rebuild the jar if any source file under src/ or pom.xml is newer than
198+
# the jar — `dir -nt file` only compares the directory mtime, which does
199+
# NOT move when files inside the directory are edited, so a plain
200+
# `[ src -nt target/customer360.jar ]` would happily reuse a stale jar
201+
# after a code change.
202+
needs_build=1
203+
if [ -f target/customer360.jar ]; then
204+
if [ -z "$(find src pom.xml -type f -newer target/customer360.jar -print -quit 2>/dev/null)" ]; then
205+
needs_build=0
206+
fi
207+
fi
208+
if [ "${needs_build}" -eq 1 ]; then
198209
say "building customer360.jar (mvn package)"
199210
mvn -q -B -DskipTests package
200211
else

sap-demo-java/docker-compose.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
# For the demo, prefer ./deploy_kind.sh (matches production topology).
66
services:
77
postgres:
8-
image: postgres:15-alpine
8+
image: postgres:16-alpine
99
container_name: customer360-postgres
1010
environment:
1111
POSTGRES_DB: customer360

sap-demo-java/k8s/postgres.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Postgres 15 for the Customer 360 local store (tags, notes, audit).
1+
# Postgres 16 for the Customer 360 local store (tags, notes, audit).
22
#
33
# Kept in a single file for demo-legibility: Secret + Service + Deployment.
44
# emptyDir volume (not PVC) — fresh DB on every pod restart, which is fine
@@ -68,7 +68,7 @@ spec:
6868
terminationGracePeriodSeconds: 15
6969
containers:
7070
- name: postgres
71-
image: postgres:15-alpine
71+
image: postgres:16-alpine
7272
imagePullPolicy: IfNotPresent
7373
ports:
7474
- name: postgres

sap-demo-java/keploy.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,4 +119,4 @@ serverPort: 0
119119
mockDownload:
120120
registryIds: []
121121

122-
# Visit [https://keploy.io/docs/running-keploy/configuration-file/] to learn about using keploy through configration file.
122+
# Visit [https://keploy.io/docs/running-keploy/configuration-file/] to learn about using keploy through configuration file.

sap-demo-java/kind-config.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,9 @@ nodes:
1414
protocol: TCP
1515
- containerPort: 443
1616
hostPort: 443
17+
protocol: TCP
18+
# The NodePort Service (k8s/service.yaml) binds 30080 on every node; this
19+
# mapping makes http://localhost:30080 reach the single-node kind cluster.
20+
- containerPort: 30080
21+
hostPort: 30080
1722
protocol: TCP

sap-demo-java/pom.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,13 @@
125125
<artifactId>spring-boot-starter-test</artifactId>
126126
<scope>test</scope>
127127
</dependency>
128+
<!-- H2 replaces Postgres at test time (@AutoConfigureTestDatabase) so
129+
the context-load smoke test can run without a live DB. -->
130+
<dependency>
131+
<groupId>com.h2database</groupId>
132+
<artifactId>h2</artifactId>
133+
<scope>test</scope>
134+
</dependency>
128135
</dependencies>
129136

130137
<build>

sap-demo-java/src/main/java/com/tricentisdemo/sap/customer360/config/SapClientConfig.java

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import org.springframework.http.client.ClientHttpRequestExecution;
1313
import org.springframework.http.client.ClientHttpRequestInterceptor;
1414
import org.springframework.http.client.ClientHttpResponse;
15-
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
1615
import org.springframework.scheduling.annotation.EnableAsync;
1716
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
1817
import org.springframework.web.client.RestTemplate;
@@ -25,15 +24,10 @@
2524
* Configures the {@link RestTemplate} used for all outbound calls to the SAP
2625
* S/4HANA Business Partner OData service.
2726
*
28-
* <p>Three interceptors are attached:
27+
* <p>Two interceptors are attached:
2928
* <ol>
3029
* <li><b>SapAuthInterceptor</b> — stamps the required {@code APIKey} header
3130
* (sandbox) or {@code Authorization: Bearer} (production tenant).</li>
32-
* <li><b>IdentityEncodingInterceptor</b> — forces {@code Accept-Encoding: identity}
33-
* so bodies are not gzip-compressed in transit. In production this is
34-
* optional; here it keeps Keploy-captured YAML mocks human-readable,
35-
* which matters for demo-grade visibility and for diff-reviewing
36-
* contract changes in pull requests.</li>
3731
* <li><b>CorrelationIdInterceptor</b> — propagates the inbound request's
3832
* correlation id into the outbound SAP call so traces chain across
3933
* the hop.</li>
@@ -77,13 +71,17 @@ public RestTemplate sapRestTemplate(RestTemplateBuilder builder) {
7771
+ "Outbound SAP calls will fail with 401.");
7872
}
7973

80-
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
81-
factory.setConnectTimeout((int) Duration.ofSeconds(connectTimeoutSeconds).toMillis());
82-
factory.setConnectionRequestTimeout((int) Duration.ofSeconds(connectTimeoutSeconds).toMillis());
83-
74+
// Spring Boot auto-selects HttpClient5 when httpclient5 is on the
75+
// classpath (see pom.xml). Setting connect+read timeouts via the
76+
// RestTemplateBuilder plumbs them through to the underlying
77+
// HttpClient5 RequestConfig (connect) and SocketConfig (soTimeout ==
78+
// read timeout), which is the only API surface that still exists in
79+
// Spring 6 — HttpComponentsClientHttpRequestFactory.setReadTimeout
80+
// was removed with the HttpClient5 migration.
8481
return builder
8582
.rootUri(baseUrl)
86-
.requestFactory(() -> factory)
83+
.setConnectTimeout(Duration.ofSeconds(connectTimeoutSeconds))
84+
.setReadTimeout(Duration.ofSeconds(readTimeoutSeconds))
8785
.additionalInterceptors(
8886
new SapAuthInterceptor(apiKey, bearerToken),
8987
new CorrelationIdInterceptor()

sap-demo-java/src/main/java/com/tricentisdemo/sap/customer360/repository/CustomerTagRepository.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@
99
import org.springframework.transaction.annotation.Transactional;
1010

1111
import java.util.List;
12+
import java.util.Optional;
1213

1314
@Repository
1415
public interface CustomerTagRepository extends JpaRepository<CustomerTag, Long> {
1516

1617
List<CustomerTag> findAllByCustomerIdOrderByCreatedAtDesc(String customerId);
1718

18-
boolean existsByCustomerIdAndTag(String customerId, String tag);
19+
Optional<CustomerTag> findByCustomerIdAndTag(String customerId, String tag);
1920

2021
@Modifying
2122
@Transactional

0 commit comments

Comments
 (0)