diff --git a/.run/petcilinic-service.run.xml b/.run/petcilinic-service.run.xml
index a2a0407b48d..0ebf79d6086 100644
--- a/.run/petcilinic-service.run.xml
+++ b/.run/petcilinic-service.run.xml
@@ -3,7 +3,7 @@
-
+
diff --git a/build.gradle b/build.gradle
index da1310b5e4e..b4de14b2c1d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -12,7 +12,7 @@ group = 'org.springframework.samples'
version = '3.0.0'
sourceCompatibility = '17'
-def OPENTELEMETRY_VERSION = '1.22.1'
+def OPENTELEMETRY_VERSION = '1.26.0'
repositories {
mavenLocal()
@@ -43,7 +43,8 @@ dependencies {
developmentOnly 'org.springframework.boot:spring-boot-devtools'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
- //Enables instrumentation using @WithSpan
+
+ //Enables instrumentation using @WithSpan
implementation("io.opentelemetry.instrumentation:opentelemetry-instrumentation-annotations:${OPENTELEMETRY_VERSION}")
implementation("io.opentelemetry.instrumentation:opentelemetry-instrumentation-api:${OPENTELEMETRY_VERSION}")
@@ -65,7 +66,7 @@ task runClientTester(type: JavaExec) {
jvmArgs("-javaagent:build/otel/opentelemetry-javaagent.jar")
systemProperty("otel.service.name", "ClientTesterOfPetClinic")
systemProperty("otel.traces.exporter", "otlp")
- environment("OTEL_RESOURCE_ATTRIBUTES", "digma.environment=INTEGRATION")
+ environment("OTEL_RESOURCE_ATTRIBUTES", "digma.environment=TEST")
systemProperty("otel.exporter.otlp.traces.endpoint", "http://localhost:5050")
environment("PETSHOP_URL", "http://localhost:9753")
diff --git a/petshop-chart/Chart.yaml b/petshop-chart/Chart.yaml
index 9984e4b20ef..d09965378f2 100644
--- a/petshop-chart/Chart.yaml
+++ b/petshop-chart/Chart.yaml
@@ -15,7 +15,7 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
-version: 0.1.0
+version: 0.1.2
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
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 8c05370c7e7..a4616e7476a 100644
--- a/src/main/java/org/springframework/samples/petclinic/domain/OwnerValidation.java
+++ b/src/main/java/org/springframework/samples/petclinic/domain/OwnerValidation.java
@@ -6,6 +6,8 @@
import io.opentelemetry.instrumentation.annotations.WithSpan;
import org.springframework.samples.petclinic.owner.Owner;
+import java.util.concurrent.ThreadLocalRandom;
+
public class OwnerValidation {
private int counter = 0;
@@ -34,11 +36,24 @@ public void ValidateOwnerWithExternalService(Owner owner) {
this.AuthServiceValidateUser(owner);
}
+ private void NewFunction(){
+
+ }
@WithSpan
- // This function and classes were generated by ChatGPT to demonstrate some mock
- // business logic
+ public boolean UserNameMustStartWithR(String usr){
+
+ if (!usr.toLowerCase().startsWith("r")){
+ return false;
+ }
+
+ return true;
+
+ }
+ @WithSpan
+ // This function and classes were generated by ChatGPT
public boolean ValidateUserAccess(String usr, String pswd, String sysCode) {
+ UserNameMustStartWithR(usr);
boolean vldUsr = usrValSvc.vldtUsr(usr);
if (!vldUsr) {
return false;
@@ -76,8 +91,9 @@ public boolean ValidateUserAccess(String usr, String pswd, String sysCode) {
@WithSpan
private synchronized void AuthServiceValidateUser(Owner owner) {
+ //This is the actual Root Cause!!
try {
- Thread.sleep(2000 + (this.counter * 100));
+ Thread.sleep(2000 + (this.counter * 100));
}
catch (InterruptedException e) {
throw new RuntimeException(e);
@@ -87,15 +103,35 @@ private synchronized void AuthServiceValidateUser(Owner owner) {
@WithSpan
public boolean checkOwnerValidity(Owner owner) {
+ this.ValidateOwnerUserBad(owner);
return ValidateOwnerUser(owner);
+
}
+
+ @WithSpan
+ private boolean ValidateOwnerUserBad(Owner owner) {{
+
+ for (int i = 0; i < 100; i++) {
+ ValidateOwner();
+ }
+ return true;
+
+
+ }}
+
+
+
+
+
+ @WithSpan
private boolean ValidateOwnerUser(Owner owner) {
Span span = otelTracer.spanBuilder("db_access_01").startSpan();
+ var max = ThreadLocalRandom.current().nextInt(90, 110 + 1);
try {
- for (int i = 0; i < 100; i++) {
+ for (int i = 0; i < max; i++) {
ValidateOwner();
}
}
@@ -106,6 +142,7 @@ private boolean ValidateOwnerUser(Owner owner) {
}
+ @WithSpan
private void ValidateOwner() {
// simulate SpanKind of DB query
// see
@@ -117,17 +154,19 @@ private void ValidateOwner() {
.startSpan();
try {
- // delay(1);
+ Thread.sleep(14);
+ }
+ catch (Exception e){
+
}
finally {
span.end();
}
}
+ @WithSpan
public void PerformValidationFlow(Owner owner) {
- if (owner.getPet("Jerry").isNew()) {
- ValidateOwner();
- }
+
}
}
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 7133eaf3f52..f2d21560cc2 100644
--- a/src/main/java/org/springframework/samples/petclinic/domain/PasswordUtils.java
+++ b/src/main/java/org/springframework/samples/petclinic/domain/PasswordUtils.java
@@ -7,7 +7,7 @@ public class PasswordUtils {
@WithSpan
public boolean vldtPswd(String usr, String pswd) {
try {
- Thread.sleep(30);
+ Thread.sleep(800);
}
catch (InterruptedException e) {
throw new RuntimeException(e);
diff --git a/src/main/java/org/springframework/samples/petclinic/order/Coupon.java b/src/main/java/org/springframework/samples/petclinic/order/Coupon.java
new file mode 100644
index 00000000000..15c0d49cb18
--- /dev/null
+++ b/src/main/java/org/springframework/samples/petclinic/order/Coupon.java
@@ -0,0 +1,7 @@
+package org.springframework.samples.petclinic.order;
+
+public class Coupon {
+ // Some fields...
+
+ // Constructor, getters and setters should be here...
+}
diff --git a/src/main/java/org/springframework/samples/petclinic/order/Customer.java b/src/main/java/org/springframework/samples/petclinic/order/Customer.java
new file mode 100644
index 00000000000..14a89fa2fb7
--- /dev/null
+++ b/src/main/java/org/springframework/samples/petclinic/order/Customer.java
@@ -0,0 +1,69 @@
+package org.springframework.samples.petclinic.order;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Customer {
+ private int customerId;
+ private int age;
+ private boolean eligible;
+ private String address;
+ private double creditScore;
+ private double accountBalance;
+ private double totalSpent;
+ private boolean vipStatus;
+ private List coupons;
+ private int bonusPoints;
+
+ // Constructor, getters and setters should be here...
+
+ public boolean isEligible() {
+ // Logic to determine eligibility
+ return true;
+ }
+
+ public boolean hasValidAddress() {
+ // Logic to validate address
+ return true;
+ }
+
+ public boolean hasGoodCreditScore() {
+ // Logic to check credit score
+ return true;
+ }
+
+ public void addCoupon(Coupon coupon) {
+ if (coupons == null) {
+ coupons = new ArrayList<>();
+ }
+ coupons.add(coupon);
+ }
+
+ public void addBonusPoints(int points) {
+ this.bonusPoints += points;
+ }
+
+ public int getCustomerId() {
+ return 0;
+ }
+
+ public int getAge() {
+ return 0;
+ }
+
+ public int getAccountBalance() {
+ return 0;
+ }
+
+ public void setAccountBalance(double v) {
+
+ }
+
+ public double getTotalSpent() {
+ return 0;
+ }
+
+ public void setVipStatus(boolean b) {
+
+ }
+}
diff --git a/src/main/java/org/springframework/samples/petclinic/order/Order.java b/src/main/java/org/springframework/samples/petclinic/order/Order.java
new file mode 100644
index 00000000000..39c227aa159
--- /dev/null
+++ b/src/main/java/org/springframework/samples/petclinic/order/Order.java
@@ -0,0 +1,28 @@
+package org.springframework.samples.petclinic.order;
+
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.util.ArrayList;
+import java.util.List;
+
+public class Order {
+ private int orderId;
+ private double totalPrice;
+ private LocalTime time;
+
+ // Constructor, getters and setters should be here...
+
+ public double getTotalPrice() {
+ // Logic to calculate total price
+ return 0;
+ }
+
+ public int getOrderId() {
+ return 0;
+ }
+
+ public LocalDateTime getTime() {
+ return null;
+ }
+}
+
diff --git a/src/main/java/org/springframework/samples/petclinic/order/OrderProcessor.java b/src/main/java/org/springframework/samples/petclinic/order/OrderProcessor.java
new file mode 100644
index 00000000000..af372d67467
--- /dev/null
+++ b/src/main/java/org/springframework/samples/petclinic/order/OrderProcessor.java
@@ -0,0 +1,104 @@
+package org.springframework.samples.petclinic.order;
+
+import org.springframework.samples.petclinic.order.Customer;
+import org.springframework.samples.petclinic.order.Order;
+import org.springframework.samples.petclinic.order.PaymentInfo;
+import org.springframework.samples.petclinic.order.Product;
+
+import java.util.*;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+
+public class OrderProcessor {
+ private final PolicyService policyService ;
+
+ public enum OrderStatus {
+ SUCCESS,
+ FAILURE,
+ PENDING,
+ CANCELLED
+ }
+
+ public OrderProcessor(){
+ this.policyService=new PolicyService();
+ }
+
+
+ public CompletableFuture processOrder(Order order, Customer customer, List productList, PaymentInfo paymentInfo) {
+ return CompletableFuture.supplyAsync(() -> {
+ if (order == null || customer == null || productList == null || productList.isEmpty() || paymentInfo == null) {
+ return OrderStatus.FAILURE;
+ }
+
+ // Initial validations
+ if (order.getOrderId() <= 0 || customer.getCustomerId() <= 0) {
+ return OrderStatus.FAILURE;
+ }
+
+ // Checking if the customer is eligible for ordering
+ if (!customer.isEligible()) {
+ if (customer.getAge() < policyService.GetUnderAgeValue()) {
+ System.out.println("Customer is under age");
+ return OrderStatus.FAILURE;
+ } else if (!customer.hasValidAddress()) {
+ System.out.println("Customer address is not valid");
+ return OrderStatus.FAILURE;
+ } else if (!customer.hasGoodCreditScore()) {
+ System.out.println("Customer credit score is not sufficient");
+ return OrderStatus.FAILURE;
+ }
+ }
+
+ // Checking if the products are available in stock
+ for (Product product : productList) {
+ if (product.getStock() <= 0) {
+ System.out.println("Product out of stock: " + product.getProductId());
+ return OrderStatus.FAILURE;
+ }
+ }
+
+ // Checking if the payment method is valid
+ if (!paymentInfo.isValid()) {
+ System.out.println("Payment method is invalid");
+ return OrderStatus.FAILURE;
+ }
+
+ // Checking if the customer has sufficient balance for the order
+ double totalOrderPrice = order.getTotalPrice();
+ if (customer.getAccountBalance() < totalOrderPrice) {
+ System.out.println("Customer does not have sufficient balance");
+ return OrderStatus.FAILURE;
+ }
+
+ // If all conditions are met, then process the order
+ for (Product product : productList) {
+ // Decrease the stock of each product asynchronously
+ CompletableFuture.runAsync(product::decreaseStock);
+ }
+
+ // Deduct the order price from the customer account balance
+ customer.setAccountBalance(customer.getAccountBalance() - totalOrderPrice);
+
+ // If the customer has spent more than a certain amount, give them VIP status
+ CompletableFuture.runAsync(() -> {
+ if (customer.getTotalSpent() + totalOrderPrice > this.policyService.GetVIPMinimum()) {
+ customer.setVipStatus(true);
+ }
+ });
+
+ // If the customer has bought a certain product, give them a coupon
+ productList.stream()
+ .filter(product -> product.getProductId() == 123)
+ .findAny()
+ .ifPresent(product -> CompletableFuture.runAsync(() -> customer.addCoupon(new Coupon())));
+
+ // If the order is placed during a certain time, add bonus points to the customer
+ if (order.getTime().getHour() >= 12 && order.getTime().getHour() <= 17) {
+ CompletableFuture.runAsync(() -> customer.addBonusPoints(100));
+ }
+
+ System.out.println("Order processed successfully");
+ return OrderStatus.SUCCESS;
+ });
+ }
+}
diff --git a/src/main/java/org/springframework/samples/petclinic/order/PaymentInfo.java b/src/main/java/org/springframework/samples/petclinic/order/PaymentInfo.java
new file mode 100644
index 00000000000..51f5bcf5527
--- /dev/null
+++ b/src/main/java/org/springframework/samples/petclinic/order/PaymentInfo.java
@@ -0,0 +1,12 @@
+package org.springframework.samples.petclinic.order;
+
+public class PaymentInfo {
+ // Some fields...
+
+ // Constructor, getters and setters should be here...
+
+ public boolean isValid() {
+ // Logic to validate payment info
+ return true;
+ }
+}
diff --git a/src/main/java/org/springframework/samples/petclinic/order/PolicyService.java b/src/main/java/org/springframework/samples/petclinic/order/PolicyService.java
new file mode 100644
index 00000000000..c033554d462
--- /dev/null
+++ b/src/main/java/org/springframework/samples/petclinic/order/PolicyService.java
@@ -0,0 +1,11 @@
+package org.springframework.samples.petclinic.order;
+
+public class PolicyService {
+ public int GetUnderAgeValue() {
+ return 0;
+ }
+
+ public int GetVIPMinimum() {
+ return 0;
+ }
+}
diff --git a/src/main/java/org/springframework/samples/petclinic/order/Product.java b/src/main/java/org/springframework/samples/petclinic/order/Product.java
new file mode 100644
index 00000000000..a16b80fd684
--- /dev/null
+++ b/src/main/java/org/springframework/samples/petclinic/order/Product.java
@@ -0,0 +1,20 @@
+package org.springframework.samples.petclinic.order;
+
+public class Product {
+ private int productId;
+ private int stock;
+
+ // Constructor, getters and setters should be here...
+
+ public void decreaseStock() {
+ // Logic to decrease stock
+ }
+
+ public int getStock() {
+ return 0;
+ }
+
+ public int getProductId() {
+ return 0;
+ }
+}
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 b27f528cf54..9df62e904c1 100644
--- a/src/main/java/org/springframework/samples/petclinic/owner/OwnerController.java
+++ b/src/main/java/org/springframework/samples/petclinic/owner/OwnerController.java
@@ -15,6 +15,7 @@
*/
package org.springframework.samples.petclinic.owner;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -22,6 +23,7 @@
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.api.trace.Tracer;
+import io.opentelemetry.context.Scope;
import io.opentelemetry.instrumentation.annotations.WithSpan;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
@@ -43,6 +45,8 @@
import jakarta.validation.Valid;
+import static io.opentelemetry.api.GlobalOpenTelemetry.getTracer;
+
/**
* @author Juergen Hoeller
* @author Ken Krebs
@@ -52,6 +56,9 @@
@Controller
class OwnerController implements InitializingBean {
+
+
+
private static final String VIEWS_OWNER_CREATE_OR_UPDATE_FORM = "owners/createOrUpdateOwnerForm";
private OwnerValidation validator;
@@ -63,7 +70,9 @@ class OwnerController implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
- this.otelTracer = openTelemetry.getTracer("OwnerController");
+ //this.otelTracer = openTelemetry.getTracer("OwnerController");
+
+ this.otelTracer = getTracer("OwnerController");
validator = new OwnerValidation(this.otelTracer);
}
@@ -87,6 +96,7 @@ public Owner findOwner(@PathVariable(name = "ownerId", required = false) Integer
@GetMapping("/owners/new")
public String initCreationForm(Map model) {
Owner owner = new Owner();
+
validator.ValidateOwnerWithExternalService(owner);
model.put("owner", owner);
validator.ValidateUserAccess("admin", "pwd", "fullaccess");
@@ -94,6 +104,7 @@ public String initCreationForm(Map model) {
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
}
+
@PostMapping("/owners/new")
public String processCreationForm(@Valid Owner owner, BindingResult result) {
if (result.hasErrors()) {
@@ -168,6 +179,7 @@ public String initUpdateOwnerForm(@PathVariable("ownerId") int ownerId, Model mo
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
}
+ @WithSpan
private static void delay(long millis) {
try {
Thread.sleep(millis);
@@ -194,6 +206,8 @@ public String processUpdateOwnerForm(@Valid Owner owner, BindingResult result,
return "redirect:/owners/{ownerId}";
}
+
+
/**
* Custom handler for displaying an owner.
* @param ownerId the ID of the owner to display