From 0e5c72d5ecb40cceb3ec61d810dc5832f5104e32 Mon Sep 17 00:00:00 2001 From: Roni Dover Date: Tue, 19 Sep 2023 23:09:31 -0700 Subject: [PATCH] jobruhnr --- docker-compose.yml | 22 +++++------ observability/tracing/collector-config.yaml | 26 +++++++------ .../tracing/docker-compose.trace.yml | 36 +----------------- pom.xml | 5 +++ .../petclinic/domain/OwnerValidation.java | 1 - .../domain/PetVaccinationStatusService.java | 12 +++++- .../petclinic/owner/OwnerController.java | 37 +++++++++++-------- .../petclinic/owner/OwnerRepository.java | 6 ++- .../petclinic/owner/PetController.java | 18 +++++---- .../petclinic/system/WelcomeController.java | 2 - src/main/resources/application.properties | 4 +- .../integration/OwnerControllerTests.java | 28 +++++--------- 12 files changed, 94 insertions(+), 103 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 0edf09743..841c53201 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,17 +1,17 @@ version: '3' services: - pet-clinic: - build: ./ - healthcheck: - test: [ "CMD", "curl", "-f", "http://localhost:8082/" ] - interval: 20s - timeout: 10s - retries: 4 - start_period: 5s - ports: - - "8082:8082" - entrypoint: java -jar app.jar + # pet-clinic: + # build: ./ + # healthcheck: + # test: [ "CMD", "curl", "-f", "http://localhost:8082/" ] + # interval: 20s + # timeout: 10s + # retries: 4 + # start_period: 5s + # ports: + # - "8082:8082" + # entrypoint: java -jar app.jar mysql: image: mysql:8.0 diff --git a/observability/tracing/collector-config.yaml b/observability/tracing/collector-config.yaml index 413b1e0ab..7315fa856 100644 --- a/observability/tracing/collector-config.yaml +++ b/observability/tracing/collector-config.yaml @@ -4,28 +4,32 @@ receivers: grpc: http: +extensions: + basicauth/client: + client_auth: + username: 738734 + password: glc_eyJvIjoiOTQzMDk3IiwibiI6Im90bHAtb3RscCIsImsiOiJEWnhpNTFsZVZWMHJYcTg5MTVqODJOOEgiLCJtIjp7InIiOiJ1cyJ9fQ== + exporters: - jaeger: - endpoint: "jaeger:14250" + otlphttp/grafana: + endpoint: https://otlp-gateway-prod-us-east-0.grafana.net/otlp + auth: + authenticator: basicauth/client tls: - insecure: true + insecure: false + otlp/digma: endpoint: ${OTLP_EXPORTER_DIGMA_COLLECTOR_API} tls: insecure: true - prometheus: - endpoint: "0.0.0.0:8889" - + processors: batch: service: + extensions: [basicauth/client] pipelines: traces: receivers: [otlp] - exporters: [otlp/digma, jaeger] - processors: [batch] - metrics: - receivers: [otlp] - exporters: [prometheus] + exporters: [otlphttp/grafana,otlp/digma] 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 f760e68a9..661c831c4 100644 --- a/observability/tracing/docker-compose.trace.yml +++ b/observability/tracing/docker-compose.trace.yml @@ -1,37 +1,7 @@ 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 - - grafana: - container_name: grafana - image: grafana/grafana-oss:latest - ports: - - 3000:3000 - - prometheus: - container_name: prometheus - image: prom/prometheus:latest - volumes: - - ./prometheus.yaml:/etc/prometheus/prometheus.yml - ports: - - "9090:9090" - extra_hosts: - - "host.docker.internal:host-gateway" +services: + collector: image: otel/opentelemetry-collector-contrib command: ["--config=/otel-local-config.yaml"] @@ -42,8 +12,6 @@ services: - "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 diff --git a/pom.xml b/pom.xml index 68eb84d5e..378d0a6d8 100644 --- a/pom.xml +++ b/pom.xml @@ -38,6 +38,11 @@ + + org.jobrunr + jobrunr-spring-boot-3-starter + 6.3.0 + org.springframework.boot 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 138760090..7dcef03c2 100644 --- a/src/main/java/org/springframework/samples/petclinic/domain/OwnerValidation.java +++ b/src/main/java/org/springframework/samples/petclinic/domain/OwnerValidation.java @@ -52,7 +52,6 @@ public class OwnerValidation { } - // This function and classes were generated by ChatGPT public boolean ValidateUserAccess(String usr, String pswd, String sysCode) { 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 289df3dcf..a18a890d4 100644 --- a/src/main/java/org/springframework/samples/petclinic/domain/PetVaccinationStatusService.java +++ b/src/main/java/org/springframework/samples/petclinic/domain/PetVaccinationStatusService.java @@ -6,6 +6,7 @@ import org.json.JSONException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.samples.petclinic.adapters.PetVaccinationService; import org.springframework.samples.petclinic.adapters.VaccinnationRecord; +import org.springframework.samples.petclinic.owner.OwnerRepository; import org.springframework.samples.petclinic.owner.Pet; import org.springframework.samples.petclinic.owner.PetVaccine; import org.springframework.stereotype.Component; @@ -13,18 +14,25 @@ import org.springframework.stereotype.Component; import java.io.IOException; import java.time.LocalDateTime; import java.time.ZoneId; +import java.util.List; @Component public class PetVaccinationStatusService { + @Autowired + private OwnerRepository ownerRepositorys; + @Autowired private PetVaccinationService adapter; @WithSpan - public void UpdateVaccinationStatus(Pet[] pets) { + public void updateVaccinationStatus(List petIds) { + + + for (Integer petId : petIds) { + var pet = ownerRepositorys.findById(petId).getPet(petId); - for (Pet pet : pets) { try { var vaccinationRecords = this.adapter.allVaccines(); for (VaccinnationRecord record : vaccinationRecords) { 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 1e3fc149e..00cf1f337 100644 --- a/src/main/java/org/springframework/samples/petclinic/owner/OwnerController.java +++ b/src/main/java/org/springframework/samples/petclinic/owner/OwnerController.java @@ -15,29 +15,24 @@ */ package org.springframework.samples.petclinic.owner; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - import io.opentelemetry.instrumentation.annotations.WithSpan; +import jakarta.validation.Valid; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; import org.springframework.samples.petclinic.domain.OwnerValidation; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; +import org.springframework.web.ErrorResponse; import org.springframework.web.bind.WebDataBinder; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.InitBinder; -import org.springframework.web.bind.annotation.ModelAttribute; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.ModelAndView; -import jakarta.validation.Valid; +import java.net.URI; +import java.util.List; +import java.util.Map; import static io.opentelemetry.api.GlobalOpenTelemetry.getTracer; @@ -56,7 +51,6 @@ class OwnerController { private OwnerValidation validator; - public OwnerController(OwnerRepository clinicService) { this.owners = clinicService; var otelTracer = getTracer("OwnerController"); @@ -64,17 +58,26 @@ class OwnerController { } - @InitBinder public void setAllowedFields(WebDataBinder dataBinder) { 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(); +// +// } @GetMapping("/owners/new") public String initCreationForm(Map model) { @@ -86,6 +89,8 @@ class OwnerController { return VIEWS_OWNER_CREATE_OR_UPDATE_FORM; } + + @PostMapping("/owners/new") public String processCreationForm(@Valid Owner owner, BindingResult result) { if (result.hasErrors()) { @@ -105,12 +110,14 @@ class OwnerController { return "owners/findOwners"; } + + @GetMapping("/owners") public String processFindForm(@RequestParam(defaultValue = "1") int page, Owner owner, BindingResult result, Model model) { validator.ValidateUserAccess("admin", "pwd", "fullaccess"); - // allow parameterless GET request for /owners to return all records + // allow parameterless GET request for /owners to return all records if (owner.getLastName() == null) { owner.setLastName(""); // empty string signifies broadest possible search } diff --git a/src/main/java/org/springframework/samples/petclinic/owner/OwnerRepository.java b/src/main/java/org/springframework/samples/petclinic/owner/OwnerRepository.java index 02df0e743..2f2e758a0 100644 --- a/src/main/java/org/springframework/samples/petclinic/owner/OwnerRepository.java +++ b/src/main/java/org/springframework/samples/petclinic/owner/OwnerRepository.java @@ -53,10 +53,14 @@ public interface OwnerRepository extends Repository { * found) */ - @Query("SELECT DISTINCT owner FROM Owner owner left join owner.pets WHERE owner.lastName LIKE :lastName% ") + @Query("SELECT DISTINCT owner FROM Owner owner left join owner.pets WHERE owner.lastName LIKE :lastName% ") @Transactional(readOnly = true) Page findByLastName(@Param("lastName") String lastName, Pageable pageable); + @Query("SELECT DISTINCT owner FROM Owner owner LEFT JOIN FETCH owner.pets LEFT JOIN FETCH pets.visits") + @Transactional(readOnly = true) + Page findByLastNameWithPetsAndVisits(@Param("lastName") String lastName, Pageable pageable); + /** * Retrieve an {@link Owner} from the data store by id. * @param id the id to search for 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 7c6c3178b..e914b791e 100644 --- a/src/main/java/org/springframework/samples/petclinic/owner/PetController.java +++ b/src/main/java/org/springframework/samples/petclinic/owner/PetController.java @@ -15,10 +15,13 @@ */ package org.springframework.samples.petclinic.owner; +import java.time.Instant; +import java.util.Arrays; import java.util.Collection; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import org.jobrunr.scheduling.BackgroundJob; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.samples.petclinic.domain.PetVaccinationStatusService; @@ -47,6 +50,7 @@ class PetController implements InitializingBean { private static final String VIEWS_PETS_CREATE_OR_UPDATE_FORM = "pets/createOrUpdatePetForm"; + private final OwnerRepository owners; @Autowired @@ -54,12 +58,10 @@ class PetController implements InitializingBean { private ExecutorService executorService; - public PetController(OwnerRepository owners) { this.owners = owners; } - @ModelAttribute("types") public Collection populatePetTypes() { return this.owners.findPetTypes(); @@ -87,7 +89,7 @@ class PetController implements InitializingBean { } @GetMapping("/pets/new") - public String initCreationForm(Owner owner, ModelMap model) { + public String initCreationForm(Owner owner, ModelMap model) { Pet pet = new Pet(); owner.addPet(pet); model.put("pet", pet); @@ -106,12 +108,13 @@ class PetController implements InitializingBean { return VIEWS_PETS_CREATE_OR_UPDATE_FORM; } - this.owners.save(owner); - this.executorService.submit(() -> { - petVaccinationStatus.UpdateVaccinationStatus(owner.getPets().toArray(Pet[]::new)); - }); + var pets = owner.getPets().toArray(Pet[]::new); +// executorService.submit( +// () -> petVaccinationStatus.updateVaccinationStatus(pets)); + var petIds = owner.getPets().stream().map(Pet::getId).toList(); + BackgroundJob.enqueue(() -> petVaccinationStatus.updateVaccinationStatus(petIds) ); return "redirect:/owners/{ownerId}"; } @@ -139,4 +142,5 @@ class PetController implements InitializingBean { this.executorService = Executors.newFixedThreadPool(5); } + } diff --git a/src/main/java/org/springframework/samples/petclinic/system/WelcomeController.java b/src/main/java/org/springframework/samples/petclinic/system/WelcomeController.java index a3074fb29..047cf8c0c 100644 --- a/src/main/java/org/springframework/samples/petclinic/system/WelcomeController.java +++ b/src/main/java/org/springframework/samples/petclinic/system/WelcomeController.java @@ -28,6 +28,4 @@ class WelcomeController { return "welcome"; } - - } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index d35812dc3..b9cbd455f 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -2,7 +2,9 @@ database=h2 spring.sql.init.schema-locations=classpath*:db/${database}/schema.sql 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 # 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 78f76523c..a285048db 100644 --- a/src/test/java/org/springframework/samples/petclinic/integration/OwnerControllerTests.java +++ b/src/test/java/org/springframework/samples/petclinic/integration/OwnerControllerTests.java @@ -73,7 +73,6 @@ public class OwnerControllerTests { Owner owner = CreateOwner(); - String newPetName = faker.dog().name(); given().contentType("multipart/form-data") .multiPart("id", "") @@ -85,12 +84,8 @@ public class OwnerControllerTests { .then() .statusCode(Matchers.not(Matchers.greaterThan(499))); - - var updatedOwner = ownerRepository.findById(owner.getId()); - assertThat(updatedOwner.getPets()) - .hasSize(2) - .extracting(Pet::getName) - .contains(newPetName); + var updatedOwner = ownerRepository.findById(owner.getId()); + assertThat(updatedOwner.getPets()).hasSize(2).extracting(Pet::getName).contains(newPetName); } @@ -99,18 +94,15 @@ public class OwnerControllerTests { Owner owner = CreateOwner(); - var ownerLinkMatcher = - String.format("**.findAll { node -> node.@href=='/owners/%s'}", - owner.getId()); + var ownerLinkMatcher = String.format("**.findAll { node -> node.@href=='/owners/%s'}", owner.getId()); - given() - .contentType(ContentType.JSON) - .when() - .get("/owners") - .then() - .contentType(ContentType.HTML) - .statusCode(200) - .body(ownerLinkMatcher,Matchers.notNullValue()); + given().contentType(ContentType.JSON) + .when() + .get("/owners") + .then() + .contentType(ContentType.HTML) + .statusCode(200) + .body(ownerLinkMatcher, Matchers.notNullValue()); }