diff --git a/observability/tracing/collector-config.yaml b/observability/tracing/collector-config.yaml
index 7315fa856..433a9eac8 100644
--- a/observability/tracing/collector-config.yaml
+++ b/observability/tracing/collector-config.yaml
@@ -11,6 +11,10 @@ extensions:
password: glc_eyJvIjoiOTQzMDk3IiwibiI6Im90bHAtb3RscCIsImsiOiJEWnhpNTFsZVZWMHJYcTg5MTVqODJOOEgiLCJtIjp7InIiOiJ1cyJ9fQ==
exporters:
+ otlp/jaeger:
+ endpoint: "jaeger:4320"
+ tls:
+ insecure: true
otlphttp/grafana:
endpoint: https://otlp-gateway-prod-us-east-0.grafana.net/otlp
auth:
@@ -31,5 +35,5 @@ service:
pipelines:
traces:
receivers: [otlp]
- exporters: [otlphttp/grafana,otlp/digma]
+ exporters: [otlphttp/grafana,otlp/digma,otlp/jaeger]
processors: [batch]
\ No newline at end of file
diff --git a/observability/tracing/docker-compose.trace.yml b/observability/tracing/docker-compose.trace.yml
index 661c831c4..f42a6dfdf 100644
--- a/observability/tracing/docker-compose.trace.yml
+++ b/observability/tracing/docker-compose.trace.yml
@@ -1,17 +1,34 @@
version: "3.6"
services:
-
+ jaeger:
+ image: jaegertracing/all-in-one:latest
+ container_name: jaeger
+ volumes:
+ - badger_data:/badger
+ ports:
+ - "16686:16686"
+ - "14250"
+ - "0.0.0.0:14268:14268"
+ environment:
+ - SPAN_STORAGE_TYPE=badger
+ - BADGER_EPHEMERAL=false
+ - BADGER_SPAN_STORE_TTL=2000h
+ - BADGER_DIRECTORY_VALUE=/badger/data
+ - BADGER_DIRECTORY_KEY=/badger/key
+
collector:
image: otel/opentelemetry-collector-contrib
command: ["--config=/otel-local-config.yaml"]
volumes:
- ./collector-config.yaml:/otel-local-config.yaml
ports:
- - "0.0.0.0:4317:4317" # OTLP receiver
+ - "0.0.0.0:4318:4318" # HTTP OTLP receiver
- "0.0.0.0:8889:8889" # METRICS
extra_hosts:
- "host.docker.internal:host-gateway"
+ depends_on:
+ - jaeger
environment:
- OTLP_EXPORTER_DIGMA_COLLECTOR_API=host.docker.internal:5050
@@ -20,4 +37,4 @@ networks:
name: tracing-network
volumes:
- badger_data:
\ No newline at end of file
+ badger_data:
diff --git a/pom.xml b/pom.xml
index 378d0a6d8..a4938757a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -40,14 +40,10 @@
org.jobrunr
- jobrunr-spring-boot-3-starter
- 6.3.0
+ jobrunr-pro-spring-boot-3-starter
+ 6.3.1
-
- org.springframework.boot
- spring-boot-starter-actuator
-
org.springframework.boot
spring-boot-starter-cache
@@ -111,11 +107,6 @@
postgresql
runtime
-
- io.micrometer
- micrometer-registry-prometheus
- runtime
-
javax.cache
@@ -168,6 +159,22 @@
android-json
0.0.20131108.vaadin1
+
+ io.opentelemetry
+ opentelemetry-exporter-otlp
+ 1.26.0
+
+
+ io.micrometer
+ micrometer-tracing-bridge-otel
+ 1.1.2
+
+
+ io.github.digma-ai
+ digma-spring-boot-micrometer-tracing-autoconf
+ 0.7.4
+
+
@@ -313,6 +320,10 @@
false
+
+ JobRunrPro
+ https://repo.jobrunr.io/private-trials-202310/
+
diff --git a/src/main/java/org/springframework/samples/petclinic/domain/OwnerValidation.java b/src/main/java/org/springframework/samples/petclinic/domain/OwnerValidation.java
index 7dcef03c2..5d308a4b0 100644
--- a/src/main/java/org/springframework/samples/petclinic/domain/OwnerValidation.java
+++ b/src/main/java/org/springframework/samples/petclinic/domain/OwnerValidation.java
@@ -53,6 +53,7 @@ public class OwnerValidation {
}
// This function and classes were generated by ChatGPT
+ @WithSpan
public boolean ValidateUserAccess(String usr, String pswd, String sysCode) {
UserNameMustStartWithR(usr);
@@ -162,8 +163,41 @@ public class OwnerValidation {
}
}
- @WithSpan
- public void PerformValidationFlow(Owner owner) {
+ public boolean PerformValidationFlow(String usr, String pswd, String sysCode) {
+ UserNameMustStartWithR(usr);
+ boolean vldUsr = usrValSvc.vldtUsr(usr);
+ if (!vldUsr) {
+ return false;
+ }
+
+ boolean vldPswd = pwdUtils.vldtPswd(usr, pswd);
+ if (!vldPswd) {
+ return false;
+ }
+
+ boolean vldUsrRole = roleSvc.vldtUsrRole(usr, sysCode);
+ if (!vldUsrRole) {
+ return false;
+ }
+
+ boolean is2FASuccess = twoFASvc.init2FA(usr);
+ if (!is2FASuccess) {
+ return false;
+ }
+
+ boolean is2FATokenValid = false;
+ int retry = 0;
+ while (retry < 3 && !is2FATokenValid) {
+ String token = twoFASvc.getTokenInput();
+ is2FATokenValid = twoFASvc.vldtToken(usr, token);
+ retry++;
+ }
+
+ if (!is2FATokenValid) {
+ return false;
+ }
+
+ return true;
}
diff --git a/src/main/java/org/springframework/samples/petclinic/domain/PasswordUtils.java b/src/main/java/org/springframework/samples/petclinic/domain/PasswordUtils.java
index ff95380e0..47d73e5b4 100644
--- a/src/main/java/org/springframework/samples/petclinic/domain/PasswordUtils.java
+++ b/src/main/java/org/springframework/samples/petclinic/domain/PasswordUtils.java
@@ -15,15 +15,10 @@ public class PasswordUtils {
return true;
}
- @WithSpan
public String encPswd(String pswd) {
- try {
- Thread.sleep(300);
- }
- catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
+
return "";
+
}
}
diff --git a/src/main/java/org/springframework/samples/petclinic/domain/PetVaccinationStatusService.java b/src/main/java/org/springframework/samples/petclinic/domain/PetVaccinationStatusService.java
index a18a890d4..01c2ee32a 100644
--- a/src/main/java/org/springframework/samples/petclinic/domain/PetVaccinationStatusService.java
+++ b/src/main/java/org/springframework/samples/petclinic/domain/PetVaccinationStatusService.java
@@ -1,6 +1,7 @@
package org.springframework.samples.petclinic.domain;
import io.opentelemetry.api.trace.Span;
+import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.instrumentation.annotations.WithSpan;
import org.json.JSONException;
import org.springframework.beans.factory.annotation.Autowired;
@@ -19,19 +20,24 @@ import java.util.List;
@Component
public class PetVaccinationStatusService {
+ public record UpdateVaccineStatusRequest(int ownerId, int petId) {
+
+ }
+
@Autowired
private OwnerRepository ownerRepositorys;
@Autowired
private PetVaccinationService adapter;
-
@WithSpan
- public void updateVaccinationStatus(List petIds) {
+ public void updateVaccinationStatus(List updateVaccineStatusRequests) {
- for (Integer petId : petIds) {
- var pet = ownerRepositorys.findById(petId).getPet(petId);
+ for (UpdateVaccineStatusRequest request : updateVaccineStatusRequests) {
+ var owner = ownerRepositorys.findById(request.ownerId);
+
+ var pet = owner.getPet(request.petId);
try {
var vaccinationRecords = this.adapter.allVaccines();
diff --git a/src/main/java/org/springframework/samples/petclinic/owner/OwnerController.java b/src/main/java/org/springframework/samples/petclinic/owner/OwnerController.java
index 00cf1f337..f7f2f78e5 100644
--- a/src/main/java/org/springframework/samples/petclinic/owner/OwnerController.java
+++ b/src/main/java/org/springframework/samples/petclinic/owner/OwnerController.java
@@ -63,21 +63,20 @@ class OwnerController {
dataBinder.setDisallowedFields("id");
}
-
@ModelAttribute("owner")
public Owner findOwner(@PathVariable(name = "ownerId", required = false) Integer ownerId) {
return ownerId == null ? new Owner() : this.owners.findById(ownerId);
}
-// @ExceptionHandler(NullPointerException.class)
-// @ResponseStatus(HttpStatus.BAD_REQUEST)
-// public ErrorResponse onIllegaArgumentException(RuntimeException npe){
-// return ErrorResponse.builder(npe,HttpStatus.NOT_FOUND, npe.getMessage())
-// .title("Not found")
-// .type(URI.create("https://api.bookmarks.com/errors/not-found"))
-// .build();
-//
-// }
+ // @ExceptionHandler(NullPointerException.class)
+ // @ResponseStatus(HttpStatus.BAD_REQUEST)
+ // public ErrorResponse onIllegaArgumentException(RuntimeException npe){
+ // return ErrorResponse.builder(npe,HttpStatus.NOT_FOUND, npe.getMessage())
+ // .title("Not found")
+ // .type(URI.create("https://api.bookmarks.com/errors/not-found"))
+ // .build();
+ //
+ // }
@GetMapping("/owners/new")
public String initCreationForm(Map model) {
@@ -89,15 +88,13 @@ class OwnerController {
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
}
-
-
@PostMapping("/owners/new")
public String processCreationForm(@Valid Owner owner, BindingResult result) {
if (result.hasErrors()) {
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
}
validator.ValidateOwnerWithExternalService(owner);
- validator.PerformValidationFlow(owner);
+ // validator.PerformValidationFlow(owner);
validator.checkOwnerValidity(owner);
this.owners.save(owner);
@@ -110,8 +107,6 @@ class OwnerController {
return "owners/findOwners";
}
-
-
@GetMapping("/owners")
public String processFindForm(@RequestParam(defaultValue = "1") int page, Owner owner, BindingResult result,
Model model) {
diff --git a/src/main/java/org/springframework/samples/petclinic/owner/PetController.java b/src/main/java/org/springframework/samples/petclinic/owner/PetController.java
index e914b791e..8ebe9de5a 100644
--- a/src/main/java/org/springframework/samples/petclinic/owner/PetController.java
+++ b/src/main/java/org/springframework/samples/petclinic/owner/PetController.java
@@ -18,6 +18,7 @@ package org.springframework.samples.petclinic.owner;
import java.time.Instant;
import java.util.Arrays;
import java.util.Collection;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -50,7 +51,6 @@ class PetController implements InitializingBean {
private static final String VIEWS_PETS_CREATE_OR_UPDATE_FORM = "pets/createOrUpdatePetForm";
-
private final OwnerRepository owners;
@Autowired
@@ -97,7 +97,8 @@ class PetController implements InitializingBean {
}
@PostMapping("/pets/new")
- public String processCreationForm(Owner owner, @Valid Pet pet, BindingResult result, ModelMap model) {
+ public String processCreationForm(Owner owner, @Valid Pet pet, BindingResult result, ModelMap model)
+ throws ExecutionException, InterruptedException {
if (StringUtils.hasLength(pet.getName()) && pet.isNew() && owner.getPet(pet.getName(), true) != null) {
result.rejectValue("name", "duplicate", "already exists");
}
@@ -109,12 +110,18 @@ class PetController implements InitializingBean {
}
this.owners.save(owner);
- var pets = owner.getPets().toArray(Pet[]::new);
-// executorService.submit(
-// () -> petVaccinationStatus.updateVaccinationStatus(pets));
+ // var pets = owner.getPets().toArray(Pet[]::new);
- var petIds = owner.getPets().stream().map(Pet::getId).toList();
- BackgroundJob.enqueue(() -> petVaccinationStatus.updateVaccinationStatus(petIds) );
+ var petRequests = owner.getPets()
+ .stream()
+ .map(x -> new PetVaccinationStatusService.UpdateVaccineStatusRequest(owner.getId(), x.getId()))
+ .toList();
+// executorService.submit(() ->
+// petVaccinationStatus.updateVaccinationStatus(petRequests)).get();
+ executorService.submit(() -> petVaccinationStatus.updateVaccinationStatus(petRequests));
+//
+// BackgroundJob.enqueue(() ->
+// petVaccinationStatus.updateVaccinationStatus(petRequests));
return "redirect:/owners/{ownerId}";
}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index b9cbd455f..81af2ca03 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -5,6 +5,9 @@ spring.sql.init.data-locations=classpath*:db/${database}/data.sql
org.jobrunr.job-scheduler.enabled=true
org.jobrunr.background-job-server.enabled=true
org.jobrunr.dashboard.enabled=true
+org.jobrunr.metrics.otel-observability.enabled=true
+org.jobrunr.metrics.enabled=true
+
# Web
spring.thymeleaf.mode=HTML
diff --git a/src/test/java/org/springframework/samples/petclinic/integration/OwnerControllerTests.java b/src/test/java/org/springframework/samples/petclinic/integration/OwnerControllerTests.java
index a285048db..9e60f34ca 100644
--- a/src/test/java/org/springframework/samples/petclinic/integration/OwnerControllerTests.java
+++ b/src/test/java/org/springframework/samples/petclinic/integration/OwnerControllerTests.java
@@ -38,24 +38,12 @@ public class OwnerControllerTests {
@LocalServerPort
private Integer port;
- @BeforeAll
- static void beforeAll() {
- postgres.start();
- }
-
- @AfterAll
- static void afterAll() {
- postgres.stop();
- }
-
@Container
@ServiceConnection
static PostgreSQLContainer> postgres = new PostgreSQLContainer<>("postgres:15-alpine");
@BeforeEach
void setUp() {
- // ownerRepository.deleteAll();
-
RestAssured.baseURI = "http://localhost:" + port;
}