diff --git a/.cursor/rules/161-java-profiling-detect.mdc b/.cursor/rules/161-java-profiling-detect.mdc
index 12b21fba..034c5a51 100644
--- a/.cursor/rules/161-java-profiling-detect.mdc
+++ b/.cursor/rules/161-java-profiling-detect.mdc
@@ -27,35 +27,22 @@ The rule ensures consistent, repeatable profiling procedures while providing the
## ⚠️ CRITICAL INSTRUCTION FOR AI ASSISTANTS ⚠️
-**WHEN USING THE PROFILING SCRIPT TEMPLATE:**
-- **COPY THE BASH SCRIPT EXACTLY** from `java-profiling-script-template.md`
+**WHEN USING THE PROFILING SCRIPT TEMPLATES:**
+- **COPY THE BASH SCRIPT EXACTLY** from `java-profiling-script-template.md` or `java-profiling-script-run-app-template.md`
- **NO MODIFICATIONS, INTERPRETATIONS, OR ENHANCEMENTS** allowed
- **USE EVERY LINE VERBATIM** - do not change logic, structure, or features
- **DO NOT CREATE YOUR OWN VERSION** - use the provided template only
-- The template script is complete, tested, and production-ready
+- The template scripts are complete, tested, and production-ready
---
This rule provides comprehensive Java application profiling using async-profiler v4.0, including automatic OS detection, profiler download, and flamegraph generation with the latest features.
-## Problem Identification
-
-Before starting the profiling process, identify what specific performance problem you're trying to solve.
-
-**Reference the profiling questions template:** [java-profiling-questions-template.md](mdc:.cursor/rules/templates/java-profiling-questions-template.md)
-
-The template categorizes problems into:
-- **Performance Bottlenecks** (CPU hotspots, inefficient algorithms, unnecessary allocations, string operations)
-- **Memory-Related Problems** (memory leaks, heap usage, object retention, off-heap issues)
-- **Concurrency and Threading Issues** (lock contention, thread pool issues, deadlocks, context switching)
-- **Garbage Collection Problems** (GC pressure, long pauses, generational issues)
-- **I/O and Network Bottlenecks** (blocking operations, connection leaks, serialization issues)
-
## Overview
Java profiling helps identify performance bottlenecks, memory leaks, and CPU hotspots in Java applications. This rule automates the process of:
1. **Problem Identification**: Determine what specific performance issue you're investigating
-2. **Process Detection**: Detecting running Java processes using `jps`
+2. **Application Setup**: Configure your application to run with profiling-friendly JVM flags
3. **Environment Setup**: Identifying the operating system and architecture
4. **Tool Download**: Downloading the appropriate async-profiler v4.0 binary
5. **Profile Execution**: Attaching to a Java process and generating flamegraphs and heatmaps
@@ -84,9 +71,10 @@ The profiling setup uses a clean folder structure with everything contained in t
```
your-project/
+├── run-with-profiler.sh # ← Step 1: Run main application with profiling JVM flags
└── profiler/ # ← All profiling-related files
├── scripts/ # ← Profiling scripts and tools
- │ └── java-profile.sh # ← Main profiling script
+ │ └── java-profile.sh # ← Step 2: Interactive profiling script
├── results/ # ← Generated profiling output
│ ├── *.html # ← Flamegraph files
│ └── *.jfr # ← JFR recording files
@@ -94,10 +82,47 @@ your-project/
└── async-profiler-*/ # ← Downloaded profiler binaries
```
+## Step-by-Step Profiling Workflow
+
+Follow this workflow in order to set up profiling for your Java application:
+
+### Step 1: Setup Application Runner Script (`run-with-profiler.sh`)
+
+**IMPORTANT**: Use the exact bash script from the template without any modification or interpretation.
+
+The application runner script is available at: [java-profiling-script-run-app-template.md](mdc:.cursor/rules/templates/java-profiling-script-run-app-template.md)
+
+**CRITICAL INSTRUCTION FOR AI ASSISTANTS:**
+- **COPY THE BASH SCRIPT EXACTLY** from the template file
+- **DO NOT MODIFY, INTERPRET, OR ENHANCE** the script content
+- **DO NOT ADD NEW FEATURES** or change the logic
+- **USE THE SCRIPT VERBATIM** - every line, comment, and function exactly as provided
+- The script is already complete and tested - no improvements needed
+
+**Script Location:**
+```
+your-project/
+└── run-with-profiler.sh # ← Run main application with the right JVM flags for profiling
+```
+
+**Setup Instructions:**
+1. Copy the **EXACT** bash script content from `java-profiling-script-run-app-template.md`
+2. Save it as `run-with-profiler.sh` in your project root
+3. Make it executable: `chmod +x run-with-profiler.sh`
+4. **NO MODIFICATIONS** to the script content are needed or allowed
+
+**Purpose:**
+- Configures JVM with profiling-friendly flags
+- Ensures proper async-profiler compatibility
+- Starts your application ready for profiling
+
**Usage:**
-- Run `./profiler/scripts/java-profile.sh` for comprehensive interactive profiling
+```bash
+# Start your application with profiling-ready JVM settings
+./run-with-profiler.sh
+```
-## Automated Profiling Script
+### Step 2: Setup Interactive Profiling Script (`java-profile.sh`)
**IMPORTANT**: Use the exact bash script from the template without any modification or interpretation.
@@ -118,37 +143,39 @@ The complete interactive profiling script is available at: [java-profiling-scrip
```
**Setup Instructions:**
-1. Copy the **EXACT** bash script content from `java-profiling-script-template.md`
-2. Save it as `profiler/scripts/java-profile.sh`
-3. Make it executable: `chmod +x profiler/scripts/java-profile.sh`
-4. **NO MODIFICATIONS** to the script content are needed or allowed
+1. Create the profiler directory structure: `mkdir -p profiler/scripts profiler/results`
+2. Copy the **EXACT** bash script content from `java-profiling-script-template.md`
+3. Save it as `profiler/scripts/java-profile.sh`
+4. Make it executable: `chmod +x profiler/scripts/java-profile.sh`
+5. **NO MODIFICATIONS** to the script content are needed or allowed
+
+**Purpose:**
+- Detects running Java processes automatically
+- Downloads and configures async-profiler v4.0
+- Provides interactive menu for different profiling scenarios
+- Generates flamegraphs and analysis reports
## Profiling Execution Workflow
-After setting up the profiling scripts, follow this execution workflow to profile your Java application and store results in the profiler/results directory:
+After setting up both scripts, follow this execution workflow:
-### Step 1: Create and Make Script Executable
+### Step 1: Start Your Application with Profiling Support
-**CRITICAL**: Use the exact script from the template without any changes:
+First, start your application using the profiling-ready runner:
```bash
-# Create the profiler directory structure
-mkdir -p profiler/scripts
-mkdir -p profiler/results
-
-# Copy the EXACT bash script from java-profiling-script-template.md
-# Save it as profiler/scripts/java-profile.sh
-# DO NOT MODIFY THE SCRIPT CONTENT - USE IT EXACTLY AS PROVIDED
-
-# Make the script executable
-chmod +x profiler/scripts/java-profile.sh
+# Start your application with JVM flags optimized for profiling
+./run-with-profiler.sh
```
-**REMINDER**: The script in `java-profiling-script-template.md` is complete and should be copied verbatim. No interpretation, enhancement, or modification is required or allowed.
+This script:
+- Applies JVM flags that make profiling more accurate
+- Ensures async-profiler can attach properly
+- Starts your application in profiling-ready mode
-### Step 2: Execute the Profiling Script
+### Step 2: Run Interactive Profiling
-Run the script from your project root directory:
+In a separate terminal, execute the interactive profiling script:
```bash
# Execute the interactive profiling script
@@ -164,7 +191,7 @@ Run the script from your project root directory:
### Step 3: Problem-Specific Profiling Commands
-Based on the problem you identified, execute these specific profiling commands:
+Based on the problem you identified, the script will execute these specific profiling commands:
#### For CPU Hotspots and Performance Bottlenecks
```bash
diff --git a/.cursor/rules/templates/java-profiling-questions-template.md b/.cursor/rules/templates/java-profiling-questions-template.md
deleted file mode 100644
index f5b8ddd2..00000000
--- a/.cursor/rules/templates/java-profiling-questions-template.md
+++ /dev/null
@@ -1,31 +0,0 @@
-# Profiling questions
-
-Make the following questions:
-
-## **Performance Bottlenecks**
-- **CPU hotspots**: Identify methods consuming excessive CPU cycles
-- **Inefficient algorithms**: Spot O(n²) operations that should be O(n log n)
-- **Unnecessary object allocations**: Find code creating millions of temporary objects
-- **String concatenation issues**: Detect inefficient string operations in loops
-
-## **Memory-Related Problems**
-- **Memory leaks**: Track objects that aren't being garbage collected
-- **Excessive heap usage**: Identify which classes/methods allocate the most memory
-- **Large object retention**: Find objects staying in memory longer than expected
-- **Off-heap memory issues**: Detect native memory leaks in JNI code
-
-## **Concurrency and Threading Issues**
-- **Lock contention**: Identify synchronized blocks causing thread blocking
-- **Thread pool exhaustion**: Find threads waiting indefinitely
-- **Deadlock conditions**: Spot circular wait conditions
-- **Context switching overhead**: Detect excessive thread switching
-
-## **Garbage Collection Problems**
-- **GC pressure**: Identify code causing frequent GC cycles
-- **Long GC pauses**: Find allocation patterns causing stop-the-world events
-- **Generational GC issues**: Spot objects promoted to old generation prematurely
-
-## **I/O and Network Bottlenecks**
-- **Blocking I/O operations**: Find threads stuck on file/network operations
-- **Database connection leaks**: Identify unclosed connections
-- **Inefficient serialization**: Spot expensive object serialization/deserialization
\ No newline at end of file
diff --git a/.cursor/rules/templates/java-profiling-script-run-app-template.md b/.cursor/rules/templates/java-profiling-script-run-app-template.md
new file mode 100644
index 00000000..0c9e1ce2
--- /dev/null
+++ b/.cursor/rules/templates/java-profiling-script-run-app-template.md
@@ -0,0 +1,343 @@
+```bash
+#!/bin/bash
+
+# Java Application Runner with Async-Profiler Support
+# This script runs Spring Boot or Quarkus applications with JVM flags optimized for async-profiler
+
+set -e
+
+# Default values
+PROFILE_MODE="cpu"
+APP_JAR=""
+APP_CLASS="info.jab.ms.MainApplication"
+HEAP_SIZE="512m"
+PROFILE_NAME="default"
+FRAMEWORK="auto"
+
+# Colors for output
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+BLUE='\033[0;34m'
+NC='\033[0m' # No Color
+
+# Function to print colored output
+log_info() {
+ echo -e "${BLUE}[INFO]${NC} $1"
+}
+
+log_warn() {
+ echo -e "${YELLOW}[WARN]${NC} $1"
+}
+
+log_error() {
+ echo -e "${RED}[ERROR]${NC} $1"
+}
+
+log_success() {
+ echo -e "${GREEN}[SUCCESS]${NC} $1"
+}
+
+# Function to show usage
+show_usage() {
+ cat << EOF
+Usage: $0 [OPTIONS]
+
+Run Spring Boot or Quarkus application with async-profiler support
+
+OPTIONS:
+ -m, --mode MODE Profiling mode: cpu, alloc, wall, lock (default: cpu)
+ -f, --framework FRAMEWORK Framework: springboot, quarkus, auto (default: auto)
+ -j, --jar PATH Path to application JAR file
+ -c, --class CLASS Main class to run (default: info.jab.ms.MainApplication)
+ -h, --heap SIZE Heap size (default: 512m)
+ -p, --profile PROFILE Profile to activate (default: default)
+ --help Show this help message
+
+FRAMEWORK DETECTION:
+ auto Automatically detect framework from pom.xml or JAR naming
+ springboot Force Spring Boot mode
+ quarkus Force Quarkus mode
+
+EXAMPLES:
+ # Auto-detect framework and run with CPU profiling
+ $0 -m cpu
+
+ # Force Spring Boot with memory allocation profiling
+ $0 -f springboot -m alloc
+
+ # Force Quarkus with custom heap size and profile
+ $0 -f quarkus -h 1g -p dev
+
+ # Run with wall-clock profiling
+ $0 -m wall
+
+EOF
+}
+
+# Parse command line arguments
+while [[ $# -gt 0 ]]; do
+ case $1 in
+ -m|--mode)
+ PROFILE_MODE="$2"
+ shift 2
+ ;;
+ -f|--framework)
+ FRAMEWORK="$2"
+ shift 2
+ ;;
+ -j|--jar)
+ APP_JAR="$2"
+ shift 2
+ ;;
+ -c|--class)
+ APP_CLASS="$2"
+ shift 2
+ ;;
+ -h|--heap)
+ HEAP_SIZE="$2"
+ shift 2
+ ;;
+ -p|--profile)
+ PROFILE_NAME="$2"
+ shift 2
+ ;;
+ --help)
+ show_usage
+ exit 0
+ ;;
+ *)
+ log_error "Unknown option: $1"
+ show_usage
+ exit 1
+ ;;
+ esac
+done
+
+# Validate profiling mode
+case $PROFILE_MODE in
+ cpu|alloc|wall|lock)
+ ;;
+ *)
+ log_error "Invalid profiling mode: $PROFILE_MODE. Use: cpu, alloc, wall, lock"
+ exit 1
+ ;;
+esac
+
+# Validate framework
+case $FRAMEWORK in
+ auto|springboot|quarkus)
+ ;;
+ *)
+ log_error "Invalid framework: $FRAMEWORK. Use: auto, springboot, quarkus"
+ exit 1
+ ;;
+esac
+
+# Function to detect framework
+detect_framework() {
+ if [[ "$FRAMEWORK" != "auto" ]]; then
+ return 0
+ fi
+
+ # Check pom.xml for framework indicators
+ if [[ -f "pom.xml" ]]; then
+ if grep -q "spring-boot-starter" pom.xml; then
+ FRAMEWORK="springboot"
+ log_info "Detected Spring Boot from pom.xml"
+ elif grep -q "quarkus-universe-bom\|quarkus-bom" pom.xml; then
+ FRAMEWORK="quarkus"
+ log_info "Detected Quarkus from pom.xml"
+ fi
+ fi
+
+ # Check for JAR files if framework still not detected
+ if [[ "$FRAMEWORK" == "auto" ]]; then
+ if [[ -n "$APP_JAR" ]]; then
+ if [[ "$APP_JAR" == *"spring-boot"* ]]; then
+ FRAMEWORK="springboot"
+ log_info "Detected Spring Boot from JAR name"
+ elif [[ "$APP_JAR" == *"quarkus"* ]] || [[ "$APP_JAR" == *"runner"* ]]; then
+ FRAMEWORK="quarkus"
+ log_info "Detected Quarkus from JAR name"
+ fi
+ else
+ # Check for JAR files in target directory
+ if ls target/*-runner.jar >/dev/null 2>&1; then
+ FRAMEWORK="quarkus"
+ log_info "Detected Quarkus from runner JAR"
+ elif ls target/*spring-boot*.jar >/dev/null 2>&1; then
+ FRAMEWORK="springboot"
+ log_info "Detected Spring Boot from JAR files"
+ fi
+ fi
+ fi
+
+ # Default to Spring Boot if still not detected
+ if [[ "$FRAMEWORK" == "auto" ]]; then
+ FRAMEWORK="springboot"
+ log_warn "Could not detect framework, defaulting to Spring Boot"
+ fi
+}
+
+# Function to set framework-specific JAR if not provided
+set_default_jar() {
+ if [[ -z "$APP_JAR" ]]; then
+ case $FRAMEWORK in
+ springboot)
+ # Look for Spring Boot JAR
+ if ls target/*spring-boot*.jar >/dev/null 2>&1; then
+ APP_JAR=$(ls target/*spring-boot*.jar | head -1)
+ else
+ # Fallback to common naming pattern
+ PROJECT_NAME=$(basename "$(pwd)")
+ APP_JAR="target/${PROJECT_NAME}-1.0-SNAPSHOT.jar"
+ fi
+ ;;
+ quarkus)
+ # Look for Quarkus runner JAR
+ if ls target/*-runner.jar >/dev/null 2>&1; then
+ APP_JAR=$(ls target/*-runner.jar | head -1)
+ else
+ # Fallback to common naming pattern
+ PROJECT_NAME=$(basename "$(pwd)")
+ APP_JAR="target/${PROJECT_NAME}-1.0-SNAPSHOT-runner.jar"
+ fi
+ ;;
+ esac
+ log_info "Using default JAR: $APP_JAR"
+ fi
+}
+
+# Detect framework and set defaults
+detect_framework
+set_default_jar
+
+# Generate timestamp for output files
+TIMESTAMP=$(date +"%Y%m%d-%H%M%S")
+
+log_info "Starting $FRAMEWORK application"
+log_info "Profile mode: $PROFILE_MODE"
+log_info "Framework: $FRAMEWORK"
+log_info "Profile: $PROFILE_NAME"
+
+# JVM flags for optimal profiling with async-profiler
+JVM_FLAGS=(
+ # Memory settings
+ "-Xms$HEAP_SIZE"
+ "-Xmx$HEAP_SIZE"
+
+ # Profiling optimization flags
+ "-XX:+UnlockDiagnosticVMOptions"
+ "-XX:+DebugNonSafepoints"
+ "-XX:+PreserveFramePointer"
+
+ # JFR settings (useful for some profiling modes)
+ "-XX:+FlightRecorder"
+ "-XX:StartFlightRecording=filename=flight-recording-${TIMESTAMP}.jfr"
+
+ # GC logging for memory leak analysis
+ "-Xlog:gc*:gc-${TIMESTAMP}.log:time,tags"
+
+ # Security settings for profiler attachment
+ "-Djdk.attach.allowAttachSelf=true"
+
+ # Optional: Disable C2 compiler for more accurate profiling (uncomment if needed)
+ # "-XX:TieredStopAtLevel=1"
+)
+
+# Framework-specific arguments
+get_app_args() {
+ case $FRAMEWORK in
+ springboot)
+ APP_ARGS=(
+ "--spring.profiles.active=$PROFILE_NAME"
+ "--logging.level.info.jab.ms=DEBUG"
+ "--server.port=8080"
+ )
+ ;;
+ quarkus)
+ APP_ARGS=(
+ "-Dquarkus.profile=$PROFILE_NAME"
+ "-Dquarkus.log.category.\"info.jab.ms\".level=DEBUG"
+ "-Dquarkus.http.port=8080"
+ )
+ ;;
+ esac
+}
+
+# Get framework-specific arguments
+get_app_args
+
+# Function to run with Maven
+run_with_maven() {
+ log_info "Running with Maven..."
+ export JAVA_TOOL_OPTIONS="${JVM_FLAGS[*]}"
+
+ case $FRAMEWORK in
+ springboot)
+ # Start Spring Boot application
+ mvn spring-boot:run \
+ -Dspring-boot.run.profiles="$PROFILE_NAME" \
+ -Dspring-boot.run.arguments="$(IFS=' '; echo "${APP_ARGS[*]}")"
+ ;;
+ quarkus)
+ # Start Quarkus application in dev mode
+ mvn quarkus:dev \
+ -Dquarkus.args="$(IFS=' '; echo "${APP_ARGS[*]}")"
+ ;;
+ esac
+}
+
+# Function to run with JAR
+run_with_jar() {
+ if [[ ! -f "$APP_JAR" ]]; then
+ log_error "JAR file not found: $APP_JAR"
+ log_info "Building the application first..."
+ case $FRAMEWORK in
+ springboot)
+ mvn clean package -DskipTests
+ ;;
+ quarkus)
+ mvn clean package -DskipTests
+ ;;
+ esac
+ fi
+
+ if [[ ! -f "$APP_JAR" ]]; then
+ log_error "Failed to build or find JAR file: $APP_JAR"
+ exit 1
+ fi
+
+ log_info "Running JAR: $APP_JAR"
+
+ # Start the application
+ java "${JVM_FLAGS[@]}" -jar "$APP_JAR" "${APP_ARGS[@]}"
+}
+
+# Function to run with class
+run_with_class() {
+ log_info "Running main class: $APP_CLASS"
+
+ # Start the application
+ java "${JVM_FLAGS[@]}" -cp "target/classes:$(mvn dependency:build-classpath -Dmdep.outputFile=/dev/stdout -q)" "$APP_CLASS" "${APP_ARGS[@]}"
+}
+
+# Main execution
+log_info "JVM Flags: ${JVM_FLAGS[*]}"
+
+# Determine how to run the application
+if [[ -f "pom.xml" ]] && command -v mvn >/dev/null 2>&1; then
+ if [[ -f "$APP_JAR" ]]; then
+ run_with_jar
+ else
+ run_with_maven
+ fi
+elif [[ -f "$APP_JAR" ]]; then
+ run_with_jar
+else
+ run_with_class
+fi
+
+log_success "Application completed!"
+```
\ No newline at end of file
diff --git a/.github/workflows/maven.yaml b/.github/workflows/maven.yaml
index 67c9d397..ab6b2fd0 100644
--- a/.github/workflows/maven.yaml
+++ b/.github/workflows/maven.yaml
@@ -27,4 +27,6 @@ jobs:
- name: Spring Boot Performance Bottleneck build
run: cd examples/spring-boot-performance-bottleneck-demo && ./mvnw --batch-mode --no-transfer-progress package --file pom.xml
- name: Spring Boot JMeter build
- run: cd examples/spring-boot-jmeter-demo && ./mvnw --batch-mode --no-transfer-progress package --file pom.xml
\ No newline at end of file
+ run: cd examples/spring-boot-jmeter-demo && ./mvnw --batch-mode --no-transfer-progress package --file pom.xml
+ - name: Quarkus build
+ run: cd examples/quarkus-demo && ./mvnw --batch-mode --no-transfer-progress package --file pom.xml
\ No newline at end of file
diff --git a/README.md b/README.md
index 16c0af75..3a877ea8 100644
--- a/README.md
+++ b/README.md
@@ -66,7 +66,7 @@ Using the Cursor rules is straightforward: simply `drag and drop` the cursor rul
### Profiling rules (Async profiler)
| Activity | Description | Prompt | Notes |
-|----------|------|--------|-------|
+|----------|-------------|--------|-------|
| [161-java-profiling-detect](.cursor/rules/161-java-profiling-detect.mdc) | Measure problems | `My Java application has performance issues - help me set up comprehensive profiling process using @161-java-profiling-detect.mdc and use the location YOUR-DEVELOPMENT/profiler` | Replace YOUR-DEVELOPMENT with your actual development path. Example: examples/spring-boot-memory-leak-demo/profiler |
| [162-java-profiling-analyze](.cursor/rules/162-java-profiling-analyze.mdc) | Analyze results | `Analyze the results located in YOUR-DEVELOPMENT/profiler and use the cursor rule @162-java-profiling-analyze` | Replace YOUR-DEVELOPMENT with your actual development path. Example: examples/spring-boot-memory-leak-demo/profiler |
| - | Code Refactoring | `Can you apply the solutions from @profiling-solutions-yyyymmdd.md in @/info to mitigate bottlenecks` | Make a refactoring with the notes from the analysis |
@@ -109,6 +109,7 @@ The rules was tested with the following examples:
- [Microservices: Spring Boot application with Memory leaks](./examples/spring-boot-memory-leak-demo/README.md)
- [Microservices: Spring Boot application with Performance Bottleneck](./examples/spring-boot-performance-bottleneck-demo/README.md)
- [Microservices: Spring Boot application with JMeter Load Testing](./examples/spring-boot-jmeter-demo/README.md)
+- [Microservices: Quarkus application](./examples/quarkus-demo/README.md)
- [Serverless: AWS Lambda](./examples/aws-lambda-hello-world/README.md)
- [Serverless: Azure Function](./examples/azure-function-hello-world/README.md)
diff --git a/examples/README.md b/examples/README.md
index 2d4cd7d8..dca53460 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -7,6 +7,6 @@
| [Spring Boot JMeter demo](spring-boot-jmeter-demo/README.md) | Spring Boot application with JMeter load testing capabilities. Includes automated test scripts and HTML report generation for performance testing. |
| [Spring Boot Memory Leak demo](spring-boot-memory-leak-demo/README.md) | Spring Boot application with intentional memory leaks. Used to demonstrate profiling and memory leak analysis techniques with JFR and flamegraphs. |
| [Spring Boot Performance Bottleneck demo](spring-boot-performance-bottleneck-demo/README.md) | Spring Boot application demonstrating common performance anti-patterns with O(n²) and O(n³) algorithms. Includes load testing and profiling tools for performance analysis. |
-
+| [Quarkus demo](quarkus-demo/README.md) | Simple Quarkus REST application demonstrating the Supersonic Subatomic Java Framework. Used to test the behaviour of Cursor rules for Java & Quarkus. |
| [AWS lambda Hello World](aws-lambda-hello-world/README.md) | Simple AWS Lambda. Used to test the behaviour of Cursor rules for Java & AWS Lambda. |
| [Azure function Hello World](azure-function-hello-world/README.md) | Simple Azure function. Used to test the behaviour of Cursor rules for Java & Azure function. |
diff --git a/examples/quarkus-demo/.dockerignore b/examples/quarkus-demo/.dockerignore
new file mode 100644
index 00000000..94810d00
--- /dev/null
+++ b/examples/quarkus-demo/.dockerignore
@@ -0,0 +1,5 @@
+*
+!target/*-runner
+!target/*-runner.jar
+!target/lib/*
+!target/quarkus-app/*
\ No newline at end of file
diff --git a/examples/quarkus-demo/.gitignore b/examples/quarkus-demo/.gitignore
new file mode 100644
index 00000000..91a800a1
--- /dev/null
+++ b/examples/quarkus-demo/.gitignore
@@ -0,0 +1,45 @@
+#Maven
+target/
+pom.xml.tag
+pom.xml.releaseBackup
+pom.xml.versionsBackup
+release.properties
+.flattened-pom.xml
+
+# Eclipse
+.project
+.classpath
+.settings/
+bin/
+
+# IntelliJ
+.idea
+*.ipr
+*.iml
+*.iws
+
+# NetBeans
+nb-configuration.xml
+
+# Visual Studio Code
+.vscode
+.factorypath
+
+# OSX
+.DS_Store
+
+# Vim
+*.swp
+*.swo
+
+# patch
+*.orig
+*.rej
+
+# Local environment
+.env
+
+# Plugin directory
+/.quarkus/cli/plugins/
+# TLS Certificates
+.certs/
diff --git a/examples/quarkus-demo/.mvn/wrapper/.gitignore b/examples/quarkus-demo/.mvn/wrapper/.gitignore
new file mode 100644
index 00000000..e72f5e8b
--- /dev/null
+++ b/examples/quarkus-demo/.mvn/wrapper/.gitignore
@@ -0,0 +1 @@
+maven-wrapper.jar
diff --git a/examples/quarkus-demo/.mvn/wrapper/MavenWrapperDownloader.java b/examples/quarkus-demo/.mvn/wrapper/MavenWrapperDownloader.java
new file mode 100644
index 00000000..fe7d037d
--- /dev/null
+++ b/examples/quarkus-demo/.mvn/wrapper/MavenWrapperDownloader.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.Authenticator;
+import java.net.PasswordAuthentication;
+import java.net.URI;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.concurrent.ThreadLocalRandom;
+
+public final class MavenWrapperDownloader {
+ private static final String WRAPPER_VERSION = "3.3.2";
+
+ private static final boolean VERBOSE = Boolean.parseBoolean(System.getenv("MVNW_VERBOSE"));
+
+ public static void main(String[] args) {
+ log("Apache Maven Wrapper Downloader " + WRAPPER_VERSION);
+
+ if (args.length != 2) {
+ System.err.println(" - ERROR wrapperUrl or wrapperJarPath parameter missing");
+ System.exit(1);
+ }
+
+ try {
+ log(" - Downloader started");
+ final URL wrapperUrl = URI.create(args[0]).toURL();
+ final String jarPath = args[1].replace("..", ""); // Sanitize path
+ final Path wrapperJarPath = Paths.get(jarPath).toAbsolutePath().normalize();
+ downloadFileFromURL(wrapperUrl, wrapperJarPath);
+ log("Done");
+ } catch (IOException e) {
+ System.err.println("- Error downloading: " + e.getMessage());
+ if (VERBOSE) {
+ e.printStackTrace();
+ }
+ System.exit(1);
+ }
+ }
+
+ private static void downloadFileFromURL(URL wrapperUrl, Path wrapperJarPath)
+ throws IOException {
+ log(" - Downloading to: " + wrapperJarPath);
+ if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
+ final String username = System.getenv("MVNW_USERNAME");
+ final char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
+ Authenticator.setDefault(new Authenticator() {
+ @Override
+ protected PasswordAuthentication getPasswordAuthentication() {
+ return new PasswordAuthentication(username, password);
+ }
+ });
+ }
+ Path temp = wrapperJarPath
+ .getParent()
+ .resolve(wrapperJarPath.getFileName() + "."
+ + Long.toUnsignedString(ThreadLocalRandom.current().nextLong()) + ".tmp");
+ try (InputStream inStream = wrapperUrl.openStream()) {
+ Files.copy(inStream, temp, StandardCopyOption.REPLACE_EXISTING);
+ Files.move(temp, wrapperJarPath, StandardCopyOption.REPLACE_EXISTING);
+ } finally {
+ Files.deleteIfExists(temp);
+ }
+ log(" - Downloader complete");
+ }
+
+ private static void log(String msg) {
+ if (VERBOSE) {
+ System.out.println(msg);
+ }
+ }
+
+}
diff --git a/examples/quarkus-demo/.mvn/wrapper/maven-wrapper.properties b/examples/quarkus-demo/.mvn/wrapper/maven-wrapper.properties
new file mode 100644
index 00000000..1a580be0
--- /dev/null
+++ b/examples/quarkus-demo/.mvn/wrapper/maven-wrapper.properties
@@ -0,0 +1,20 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+wrapperVersion=3.3.2
+distributionType=source
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip
+wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar
\ No newline at end of file
diff --git a/examples/quarkus-demo/README.md b/examples/quarkus-demo/README.md
new file mode 100644
index 00000000..05b69117
--- /dev/null
+++ b/examples/quarkus-demo/README.md
@@ -0,0 +1,62 @@
+# quarkus-demo
+
+This project uses Quarkus, the Supersonic Subatomic Java Framework.
+
+If you want to learn more about Quarkus, please visit its website: .
+
+## Running the application in dev mode
+
+You can run your application in dev mode that enables live coding using:
+
+```shell script
+./mvnw quarkus:dev
+```
+
+> **_NOTE:_** Quarkus now ships with a Dev UI, which is available in dev mode only at .
+
+## Packaging and running the application
+
+The application can be packaged using:
+
+```shell script
+./mvnw package
+```
+
+It produces the `quarkus-run.jar` file in the `target/quarkus-app/` directory.
+Be aware that it’s not an _über-jar_ as the dependencies are copied into the `target/quarkus-app/lib/` directory.
+
+The application is now runnable using `java -jar target/quarkus-app/quarkus-run.jar`.
+
+If you want to build an _über-jar_, execute the following command:
+
+```shell script
+./mvnw package -Dquarkus.package.jar.type=uber-jar
+```
+
+The application, packaged as an _über-jar_, is now runnable using `java -jar target/*-runner.jar`.
+
+## Creating a native executable
+
+You can create a native executable using:
+
+```shell script
+./mvnw package -Dnative
+```
+
+Or, if you don't have GraalVM installed, you can run the native executable build in a container using:
+
+```shell script
+./mvnw package -Dnative -Dquarkus.native.container-build=true
+```
+
+You can then execute your native executable with: `./target/quarkus-demo-1.0.0-SNAPSHOT-runner`
+
+If you want to learn more about building native executables, please consult .
+
+## Provided Code
+
+### REST
+
+Easily start your REST Web Services
+
+[Related guide section...](https://quarkus.io/guides/getting-started-reactive#reactive-jax-rs-resources)
diff --git a/examples/quarkus-demo/mvnw b/examples/quarkus-demo/mvnw
new file mode 100755
index 00000000..5e9618ca
--- /dev/null
+++ b/examples/quarkus-demo/mvnw
@@ -0,0 +1,332 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Apache Maven Wrapper startup batch script, version 3.3.2
+#
+# Required ENV vars:
+# ------------------
+# JAVA_HOME - location of a JDK home dir
+#
+# Optional ENV vars
+# -----------------
+# MAVEN_OPTS - parameters passed to the Java VM when running Maven
+# e.g. to debug Maven itself, use
+# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+# ----------------------------------------------------------------------------
+
+if [ -z "$MAVEN_SKIP_RC" ]; then
+
+ if [ -f /usr/local/etc/mavenrc ]; then
+ . /usr/local/etc/mavenrc
+ fi
+
+ if [ -f /etc/mavenrc ]; then
+ . /etc/mavenrc
+ fi
+
+ if [ -f "$HOME/.mavenrc" ]; then
+ . "$HOME/.mavenrc"
+ fi
+
+fi
+
+# OS specific support. $var _must_ be set to either true or false.
+cygwin=false
+darwin=false
+mingw=false
+case "$(uname)" in
+CYGWIN*) cygwin=true ;;
+MINGW*) mingw=true ;;
+Darwin*)
+ darwin=true
+ # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
+ # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
+ if [ -z "$JAVA_HOME" ]; then
+ if [ -x "/usr/libexec/java_home" ]; then
+ JAVA_HOME="$(/usr/libexec/java_home)"
+ export JAVA_HOME
+ else
+ JAVA_HOME="/Library/Java/Home"
+ export JAVA_HOME
+ fi
+ fi
+ ;;
+esac
+
+if [ -z "$JAVA_HOME" ]; then
+ if [ -r /etc/gentoo-release ]; then
+ JAVA_HOME=$(java-config --jre-home)
+ fi
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin; then
+ [ -n "$JAVA_HOME" ] \
+ && JAVA_HOME=$(cygpath --unix "$JAVA_HOME")
+ [ -n "$CLASSPATH" ] \
+ && CLASSPATH=$(cygpath --path --unix "$CLASSPATH")
+fi
+
+# For Mingw, ensure paths are in UNIX format before anything is touched
+if $mingw; then
+ [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] \
+ && JAVA_HOME="$(
+ cd "$JAVA_HOME" || (
+ echo "cannot cd into $JAVA_HOME." >&2
+ exit 1
+ )
+ pwd
+ )"
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+ javaExecutable="$(which javac)"
+ if [ -n "$javaExecutable" ] && ! [ "$(expr "$javaExecutable" : '\([^ ]*\)')" = "no" ]; then
+ # readlink(1) is not available as standard on Solaris 10.
+ readLink=$(which readlink)
+ if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then
+ if $darwin; then
+ javaHome="$(dirname "$javaExecutable")"
+ javaExecutable="$(cd "$javaHome" && pwd -P)/javac"
+ else
+ javaExecutable="$(readlink -f "$javaExecutable")"
+ fi
+ javaHome="$(dirname "$javaExecutable")"
+ javaHome=$(expr "$javaHome" : '\(.*\)/bin')
+ JAVA_HOME="$javaHome"
+ export JAVA_HOME
+ fi
+ fi
+fi
+
+if [ -z "$JAVACMD" ]; then
+ if [ -n "$JAVA_HOME" ]; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ]; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ else
+ JAVACMD="$(
+ \unset -f command 2>/dev/null
+ \command -v java
+ )"
+ fi
+fi
+
+if [ ! -x "$JAVACMD" ]; then
+ echo "Error: JAVA_HOME is not defined correctly." >&2
+ echo " We cannot execute $JAVACMD" >&2
+ exit 1
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+ echo "Warning: JAVA_HOME environment variable is not set." >&2
+fi
+
+# traverses directory structure from process work directory to filesystem root
+# first directory with .mvn subdirectory is considered project base directory
+find_maven_basedir() {
+ if [ -z "$1" ]; then
+ echo "Path not specified to find_maven_basedir" >&2
+ return 1
+ fi
+
+ basedir="$1"
+ wdir="$1"
+ while [ "$wdir" != '/' ]; do
+ if [ -d "$wdir"/.mvn ]; then
+ basedir=$wdir
+ break
+ fi
+ # workaround for JBEAP-8937 (on Solaris 10/Sparc)
+ if [ -d "${wdir}" ]; then
+ wdir=$(
+ cd "$wdir/.." || exit 1
+ pwd
+ )
+ fi
+ # end of workaround
+ done
+ printf '%s' "$(
+ cd "$basedir" || exit 1
+ pwd
+ )"
+}
+
+# concatenates all lines of a file
+concat_lines() {
+ if [ -f "$1" ]; then
+ # Remove \r in case we run on Windows within Git Bash
+ # and check out the repository with auto CRLF management
+ # enabled. Otherwise, we may read lines that are delimited with
+ # \r\n and produce $'-Xarg\r' rather than -Xarg due to word
+ # splitting rules.
+ tr -s '\r\n' ' ' <"$1"
+ fi
+}
+
+log() {
+ if [ "$MVNW_VERBOSE" = true ]; then
+ printf '%s\n' "$1"
+ fi
+}
+
+BASE_DIR=$(find_maven_basedir "$(dirname "$0")")
+if [ -z "$BASE_DIR" ]; then
+ exit 1
+fi
+
+MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
+export MAVEN_PROJECTBASEDIR
+log "$MAVEN_PROJECTBASEDIR"
+
+##########################################################################################
+# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+# This allows using the maven wrapper in projects that prohibit checking in binary data.
+##########################################################################################
+wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar"
+if [ -r "$wrapperJarPath" ]; then
+ log "Found $wrapperJarPath"
+else
+ log "Couldn't find $wrapperJarPath, downloading it ..."
+
+ if [ -n "$MVNW_REPOURL" ]; then
+ wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar"
+ else
+ wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar"
+ fi
+ while IFS="=" read -r key value; do
+ # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' )
+ safeValue=$(echo "$value" | tr -d '\r')
+ case "$key" in wrapperUrl)
+ wrapperUrl="$safeValue"
+ break
+ ;;
+ esac
+ done <"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
+ log "Downloading from: $wrapperUrl"
+
+ if $cygwin; then
+ wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath")
+ fi
+
+ if command -v wget >/dev/null; then
+ log "Found wget ... using wget"
+ [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet"
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
+ else
+ wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
+ fi
+ elif command -v curl >/dev/null; then
+ log "Found curl ... using curl"
+ [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent"
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
+ else
+ curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
+ fi
+ else
+ log "Falling back to using Java to download"
+ javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java"
+ javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class"
+ # For Cygwin, switch paths to Windows format before running javac
+ if $cygwin; then
+ javaSource=$(cygpath --path --windows "$javaSource")
+ javaClass=$(cygpath --path --windows "$javaClass")
+ fi
+ if [ -e "$javaSource" ]; then
+ if [ ! -e "$javaClass" ]; then
+ log " - Compiling MavenWrapperDownloader.java ..."
+ ("$JAVA_HOME/bin/javac" "$javaSource")
+ fi
+ if [ -e "$javaClass" ]; then
+ log " - Running MavenWrapperDownloader.java ..."
+ ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath"
+ fi
+ fi
+ fi
+fi
+##########################################################################################
+# End of extension
+##########################################################################################
+
+# If specified, validate the SHA-256 sum of the Maven wrapper jar file
+wrapperSha256Sum=""
+while IFS="=" read -r key value; do
+ case "$key" in wrapperSha256Sum)
+ wrapperSha256Sum=$value
+ break
+ ;;
+ esac
+done <"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
+if [ -n "$wrapperSha256Sum" ]; then
+ wrapperSha256Result=false
+ if command -v sha256sum >/dev/null; then
+ if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c >/dev/null 2>&1; then
+ wrapperSha256Result=true
+ fi
+ elif command -v shasum >/dev/null; then
+ if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c >/dev/null 2>&1; then
+ wrapperSha256Result=true
+ fi
+ else
+ echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2
+ echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." >&2
+ exit 1
+ fi
+ if [ $wrapperSha256Result = false ]; then
+ echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2
+ echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2
+ echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2
+ exit 1
+ fi
+fi
+
+MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+ [ -n "$JAVA_HOME" ] \
+ && JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME")
+ [ -n "$CLASSPATH" ] \
+ && CLASSPATH=$(cygpath --path --windows "$CLASSPATH")
+ [ -n "$MAVEN_PROJECTBASEDIR" ] \
+ && MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR")
+fi
+
+# Provide a "standardized" way to retrieve the CLI args that will
+# work with both Windows and non-Windows executions.
+MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*"
+export MAVEN_CMD_LINE_ARGS
+
+WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+# shellcheck disable=SC2086 # safe args
+exec "$JAVACMD" \
+ $MAVEN_OPTS \
+ $MAVEN_DEBUG_OPTS \
+ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
+ "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
+ ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
diff --git a/examples/quarkus-demo/mvnw.cmd b/examples/quarkus-demo/mvnw.cmd
new file mode 100644
index 00000000..4136715f
--- /dev/null
+++ b/examples/quarkus-demo/mvnw.cmd
@@ -0,0 +1,206 @@
+@REM ----------------------------------------------------------------------------
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM ----------------------------------------------------------------------------
+
+@REM ----------------------------------------------------------------------------
+@REM Apache Maven Wrapper startup batch script, version 3.3.2
+@REM
+@REM Required ENV vars:
+@REM JAVA_HOME - location of a JDK home dir
+@REM
+@REM Optional ENV vars
+@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
+@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
+@REM e.g. to debug Maven itself, use
+@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+@REM ----------------------------------------------------------------------------
+
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
+@echo off
+@REM set title of command window
+title %0
+@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
+@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
+
+@REM set %HOME% to equivalent of $HOME
+if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
+
+@REM Execute a user defined script before this one
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
+if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
+if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
+:skipRcPre
+
+@setlocal
+
+set ERROR_CODE=0
+
+@REM To isolate internal variables from possible post scripts, we use another setlocal
+@setlocal
+
+@REM ==== START VALIDATION ====
+if not "%JAVA_HOME%" == "" goto OkJHome
+
+echo. >&2
+echo Error: JAVA_HOME not found in your environment. >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo. >&2
+goto error
+
+:OkJHome
+if exist "%JAVA_HOME%\bin\java.exe" goto init
+
+echo. >&2
+echo Error: JAVA_HOME is set to an invalid directory. >&2
+echo JAVA_HOME = "%JAVA_HOME%" >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo. >&2
+goto error
+
+@REM ==== END VALIDATION ====
+
+:init
+
+@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
+@REM Fallback to current working directory if not found.
+
+set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
+IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
+
+set EXEC_DIR=%CD%
+set WDIR=%EXEC_DIR%
+:findBaseDir
+IF EXIST "%WDIR%"\.mvn goto baseDirFound
+cd ..
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
+set WDIR=%CD%
+goto findBaseDir
+
+:baseDirFound
+set MAVEN_PROJECTBASEDIR=%WDIR%
+cd "%EXEC_DIR%"
+goto endDetectBaseDir
+
+:baseDirNotFound
+set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
+cd "%EXEC_DIR%"
+
+:endDetectBaseDir
+
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
+
+@setlocal EnableExtensions EnableDelayedExpansion
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
+
+:endReadAdditionalConfig
+
+SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
+set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
+set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar"
+
+FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+ IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B
+)
+
+@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
+if exist %WRAPPER_JAR% (
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Found %WRAPPER_JAR%
+ )
+) else (
+ if not "%MVNW_REPOURL%" == "" (
+ SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar"
+ )
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Couldn't find %WRAPPER_JAR%, downloading it ...
+ echo Downloading from: %WRAPPER_URL%
+ )
+
+ powershell -Command "&{"^
+ "$webclient = new-object System.Net.WebClient;"^
+ "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
+ "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
+ "}"^
+ "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^
+ "}"
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Finished downloading %WRAPPER_JAR%
+ )
+)
+@REM End of extension
+
+@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file
+SET WRAPPER_SHA_256_SUM=""
+FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+ IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B
+)
+IF NOT %WRAPPER_SHA_256_SUM%=="" (
+ powershell -Command "&{"^
+ "Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash;"^
+ "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^
+ "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^
+ " Write-Error 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^
+ " Write-Error 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^
+ " Write-Error 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^
+ " exit 1;"^
+ "}"^
+ "}"
+ if ERRORLEVEL 1 goto error
+)
+
+@REM Provide a "standardized" way to retrieve the CLI args that will
+@REM work with both Windows and non-Windows executions.
+set MAVEN_CMD_LINE_ARGS=%*
+
+%MAVEN_JAVA_EXE% ^
+ %JVM_CONFIG_MAVEN_PROPS% ^
+ %MAVEN_OPTS% ^
+ %MAVEN_DEBUG_OPTS% ^
+ -classpath %WRAPPER_JAR% ^
+ "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
+ %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+set ERROR_CODE=1
+
+:end
+@endlocal & set ERROR_CODE=%ERROR_CODE%
+
+if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
+if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
+if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
+:skipRcPost
+
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
+if "%MAVEN_BATCH_PAUSE%"=="on" pause
+
+if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
+
+cmd /C exit /B %ERROR_CODE%
diff --git a/examples/quarkus-demo/pom.xml b/examples/quarkus-demo/pom.xml
new file mode 100644
index 00000000..f386dc9b
--- /dev/null
+++ b/examples/quarkus-demo/pom.xml
@@ -0,0 +1,124 @@
+
+
+ 4.0.0
+ org.acme
+ quarkus-demo
+ 1.0.0-SNAPSHOT
+
+
+ 3.14.0
+ 21
+ UTF-8
+ UTF-8
+ quarkus-bom
+ io.quarkus.platform
+ 3.24.1
+ true
+ 3.5.3
+
+
+
+
+
+ ${quarkus.platform.group-id}
+ ${quarkus.platform.artifact-id}
+ ${quarkus.platform.version}
+ pom
+ import
+
+
+
+
+
+
+ io.quarkus
+ quarkus-arc
+
+
+ io.quarkus
+ quarkus-rest
+
+
+ io.quarkus
+ quarkus-junit5
+ test
+
+
+ io.rest-assured
+ rest-assured
+ test
+
+
+
+
+
+
+ ${quarkus.platform.group-id}
+ quarkus-maven-plugin
+ ${quarkus.platform.version}
+ true
+
+
+
+ build
+ generate-code
+ generate-code-tests
+ native-image-agent
+
+
+
+
+
+ maven-compiler-plugin
+ ${compiler-plugin.version}
+
+ true
+
+
+
+ maven-surefire-plugin
+ ${surefire-plugin.version}
+
+
+ org.jboss.logmanager.LogManager
+ ${maven.home}
+
+
+
+
+ maven-failsafe-plugin
+ ${surefire-plugin.version}
+
+
+
+ integration-test
+ verify
+
+
+
+
+
+ ${project.build.directory}/${project.build.finalName}-runner
+ org.jboss.logmanager.LogManager
+ ${maven.home}
+
+
+
+
+
+
+
+
+ native
+
+
+ native
+
+
+
+ false
+ true
+
+
+
+
diff --git a/examples/quarkus-demo/run-with-profiler.sh b/examples/quarkus-demo/run-with-profiler.sh
new file mode 100644
index 00000000..533283d2
--- /dev/null
+++ b/examples/quarkus-demo/run-with-profiler.sh
@@ -0,0 +1,341 @@
+#!/bin/bash
+
+# Java Application Runner with Async-Profiler Support
+# This script runs Spring Boot or Quarkus applications with JVM flags optimized for async-profiler
+
+set -e
+
+# Default values
+PROFILE_MODE="cpu"
+APP_JAR=""
+APP_CLASS="info.jab.ms.MainApplication"
+HEAP_SIZE="512m"
+PROFILE_NAME="default"
+FRAMEWORK="auto"
+
+# Colors for output
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+BLUE='\033[0;34m'
+NC='\033[0m' # No Color
+
+# Function to print colored output
+log_info() {
+ echo -e "${BLUE}[INFO]${NC} $1"
+}
+
+log_warn() {
+ echo -e "${YELLOW}[WARN]${NC} $1"
+}
+
+log_error() {
+ echo -e "${RED}[ERROR]${NC} $1"
+}
+
+log_success() {
+ echo -e "${GREEN}[SUCCESS]${NC} $1"
+}
+
+# Function to show usage
+show_usage() {
+ cat << EOF
+Usage: $0 [OPTIONS]
+
+Run Spring Boot or Quarkus application with async-profiler support
+
+OPTIONS:
+ -m, --mode MODE Profiling mode: cpu, alloc, wall, lock (default: cpu)
+ -f, --framework FRAMEWORK Framework: springboot, quarkus, auto (default: auto)
+ -j, --jar PATH Path to application JAR file
+ -c, --class CLASS Main class to run (default: info.jab.ms.MainApplication)
+ -h, --heap SIZE Heap size (default: 512m)
+ -p, --profile PROFILE Profile to activate (default: default)
+ --help Show this help message
+
+FRAMEWORK DETECTION:
+ auto Automatically detect framework from pom.xml or JAR naming
+ springboot Force Spring Boot mode
+ quarkus Force Quarkus mode
+
+EXAMPLES:
+ # Auto-detect framework and run with CPU profiling
+ $0 -m cpu
+
+ # Force Spring Boot with memory allocation profiling
+ $0 -f springboot -m alloc
+
+ # Force Quarkus with custom heap size and profile
+ $0 -f quarkus -h 1g -p dev
+
+ # Run with wall-clock profiling
+ $0 -m wall
+
+EOF
+}
+
+# Parse command line arguments
+while [[ $# -gt 0 ]]; do
+ case $1 in
+ -m|--mode)
+ PROFILE_MODE="$2"
+ shift 2
+ ;;
+ -f|--framework)
+ FRAMEWORK="$2"
+ shift 2
+ ;;
+ -j|--jar)
+ APP_JAR="$2"
+ shift 2
+ ;;
+ -c|--class)
+ APP_CLASS="$2"
+ shift 2
+ ;;
+ -h|--heap)
+ HEAP_SIZE="$2"
+ shift 2
+ ;;
+ -p|--profile)
+ PROFILE_NAME="$2"
+ shift 2
+ ;;
+ --help)
+ show_usage
+ exit 0
+ ;;
+ *)
+ log_error "Unknown option: $1"
+ show_usage
+ exit 1
+ ;;
+ esac
+done
+
+# Validate profiling mode
+case $PROFILE_MODE in
+ cpu|alloc|wall|lock)
+ ;;
+ *)
+ log_error "Invalid profiling mode: $PROFILE_MODE. Use: cpu, alloc, wall, lock"
+ exit 1
+ ;;
+esac
+
+# Validate framework
+case $FRAMEWORK in
+ auto|springboot|quarkus)
+ ;;
+ *)
+ log_error "Invalid framework: $FRAMEWORK. Use: auto, springboot, quarkus"
+ exit 1
+ ;;
+esac
+
+# Function to detect framework
+detect_framework() {
+ if [[ "$FRAMEWORK" != "auto" ]]; then
+ return 0
+ fi
+
+ # Check pom.xml for framework indicators
+ if [[ -f "pom.xml" ]]; then
+ if grep -q "spring-boot-starter" pom.xml; then
+ FRAMEWORK="springboot"
+ log_info "Detected Spring Boot from pom.xml"
+ elif grep -q "quarkus-universe-bom\|quarkus-bom" pom.xml; then
+ FRAMEWORK="quarkus"
+ log_info "Detected Quarkus from pom.xml"
+ fi
+ fi
+
+ # Check for JAR files if framework still not detected
+ if [[ "$FRAMEWORK" == "auto" ]]; then
+ if [[ -n "$APP_JAR" ]]; then
+ if [[ "$APP_JAR" == *"spring-boot"* ]]; then
+ FRAMEWORK="springboot"
+ log_info "Detected Spring Boot from JAR name"
+ elif [[ "$APP_JAR" == *"quarkus"* ]] || [[ "$APP_JAR" == *"runner"* ]]; then
+ FRAMEWORK="quarkus"
+ log_info "Detected Quarkus from JAR name"
+ fi
+ else
+ # Check for JAR files in target directory
+ if ls target/*-runner.jar >/dev/null 2>&1; then
+ FRAMEWORK="quarkus"
+ log_info "Detected Quarkus from runner JAR"
+ elif ls target/*spring-boot*.jar >/dev/null 2>&1; then
+ FRAMEWORK="springboot"
+ log_info "Detected Spring Boot from JAR files"
+ fi
+ fi
+ fi
+
+ # Default to Spring Boot if still not detected
+ if [[ "$FRAMEWORK" == "auto" ]]; then
+ FRAMEWORK="springboot"
+ log_warn "Could not detect framework, defaulting to Spring Boot"
+ fi
+}
+
+# Function to set framework-specific JAR if not provided
+set_default_jar() {
+ if [[ -z "$APP_JAR" ]]; then
+ case $FRAMEWORK in
+ springboot)
+ # Look for Spring Boot JAR
+ if ls target/*spring-boot*.jar >/dev/null 2>&1; then
+ APP_JAR=$(ls target/*spring-boot*.jar | head -1)
+ else
+ # Fallback to common naming pattern
+ PROJECT_NAME=$(basename "$(pwd)")
+ APP_JAR="target/${PROJECT_NAME}-1.0-SNAPSHOT.jar"
+ fi
+ ;;
+ quarkus)
+ # Look for Quarkus runner JAR
+ if ls target/*-runner.jar >/dev/null 2>&1; then
+ APP_JAR=$(ls target/*-runner.jar | head -1)
+ else
+ # Fallback to common naming pattern
+ PROJECT_NAME=$(basename "$(pwd)")
+ APP_JAR="target/${PROJECT_NAME}-1.0-SNAPSHOT-runner.jar"
+ fi
+ ;;
+ esac
+ log_info "Using default JAR: $APP_JAR"
+ fi
+}
+
+# Detect framework and set defaults
+detect_framework
+set_default_jar
+
+# Generate timestamp for output files
+TIMESTAMP=$(date +"%Y%m%d-%H%M%S")
+
+log_info "Starting $FRAMEWORK application"
+log_info "Profile mode: $PROFILE_MODE"
+log_info "Framework: $FRAMEWORK"
+log_info "Profile: $PROFILE_NAME"
+
+# JVM flags for optimal profiling with async-profiler
+JVM_FLAGS=(
+ # Memory settings
+ "-Xms$HEAP_SIZE"
+ "-Xmx$HEAP_SIZE"
+
+ # Profiling optimization flags
+ "-XX:+UnlockDiagnosticVMOptions"
+ "-XX:+DebugNonSafepoints"
+ "-XX:+PreserveFramePointer"
+
+ # JFR settings (useful for some profiling modes)
+ "-XX:+FlightRecorder"
+ "-XX:StartFlightRecording=filename=flight-recording-${TIMESTAMP}.jfr"
+
+ # GC logging for memory leak analysis
+ "-Xlog:gc*:gc-${TIMESTAMP}.log:time,tags"
+
+ # Security settings for profiler attachment
+ "-Djdk.attach.allowAttachSelf=true"
+
+ # Optional: Disable C2 compiler for more accurate profiling (uncomment if needed)
+ # "-XX:TieredStopAtLevel=1"
+)
+
+# Framework-specific arguments
+get_app_args() {
+ case $FRAMEWORK in
+ springboot)
+ APP_ARGS=(
+ "--spring.profiles.active=$PROFILE_NAME"
+ "--logging.level.info.jab.ms=DEBUG"
+ "--server.port=8080"
+ )
+ ;;
+ quarkus)
+ APP_ARGS=(
+ "-Dquarkus.profile=$PROFILE_NAME"
+ "-Dquarkus.log.category.\"info.jab.ms\".level=DEBUG"
+ "-Dquarkus.http.port=8080"
+ )
+ ;;
+ esac
+}
+
+# Get framework-specific arguments
+get_app_args
+
+# Function to run with Maven
+run_with_maven() {
+ log_info "Running with Maven..."
+ export JAVA_TOOL_OPTIONS="${JVM_FLAGS[*]}"
+
+ case $FRAMEWORK in
+ springboot)
+ # Start Spring Boot application
+ mvn spring-boot:run \
+ -Dspring-boot.run.profiles="$PROFILE_NAME" \
+ -Dspring-boot.run.arguments="$(IFS=' '; echo "${APP_ARGS[*]}")"
+ ;;
+ quarkus)
+ # Start Quarkus application in dev mode
+ mvn quarkus:dev \
+ -Dquarkus.args="$(IFS=' '; echo "${APP_ARGS[*]}")"
+ ;;
+ esac
+}
+
+# Function to run with JAR
+run_with_jar() {
+ if [[ ! -f "$APP_JAR" ]]; then
+ log_error "JAR file not found: $APP_JAR"
+ log_info "Building the application first..."
+ case $FRAMEWORK in
+ springboot)
+ mvn clean package -DskipTests
+ ;;
+ quarkus)
+ mvn clean package -DskipTests
+ ;;
+ esac
+ fi
+
+ if [[ ! -f "$APP_JAR" ]]; then
+ log_error "Failed to build or find JAR file: $APP_JAR"
+ exit 1
+ fi
+
+ log_info "Running JAR: $APP_JAR"
+
+ # Start the application
+ java "${JVM_FLAGS[@]}" -jar "$APP_JAR" "${APP_ARGS[@]}"
+}
+
+# Function to run with class
+run_with_class() {
+ log_info "Running main class: $APP_CLASS"
+
+ # Start the application
+ java "${JVM_FLAGS[@]}" -cp "target/classes:$(mvn dependency:build-classpath -Dmdep.outputFile=/dev/stdout -q)" "$APP_CLASS" "${APP_ARGS[@]}"
+}
+
+# Main execution
+log_info "JVM Flags: ${JVM_FLAGS[*]}"
+
+# Determine how to run the application
+if [[ -f "pom.xml" ]] && command -v mvn >/dev/null 2>&1; then
+ if [[ -f "$APP_JAR" ]]; then
+ run_with_jar
+ else
+ run_with_maven
+ fi
+elif [[ -f "$APP_JAR" ]]; then
+ run_with_jar
+else
+ run_with_class
+fi
+
+log_success "Application completed!"
\ No newline at end of file
diff --git a/examples/quarkus-demo/src/main/docker/Dockerfile.jvm b/examples/quarkus-demo/src/main/docker/Dockerfile.jvm
new file mode 100644
index 00000000..d77bfa34
--- /dev/null
+++ b/examples/quarkus-demo/src/main/docker/Dockerfile.jvm
@@ -0,0 +1,98 @@
+####
+# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode
+#
+# Before building the container image run:
+#
+# ./mvnw package
+#
+# Then, build the image with:
+#
+# docker build -f src/main/docker/Dockerfile.jvm -t quarkus/quarkus-demo-jvm .
+#
+# Then run the container using:
+#
+# docker run -i --rm -p 8080:8080 quarkus/quarkus-demo-jvm
+#
+# If you want to include the debug port into your docker image
+# you will have to expose the debug port (default 5005 being the default) like this : EXPOSE 8080 5005.
+# Additionally you will have to set -e JAVA_DEBUG=true and -e JAVA_DEBUG_PORT=*:5005
+# when running the container
+#
+# Then run the container using :
+#
+# docker run -i --rm -p 8080:8080 quarkus/quarkus-demo-jvm
+#
+# This image uses the `run-java.sh` script to run the application.
+# This scripts computes the command line to execute your Java application, and
+# includes memory/GC tuning.
+# You can configure the behavior using the following environment properties:
+# - JAVA_OPTS: JVM options passed to the `java` command (example: "-verbose:class") - Be aware that this will override
+# the default JVM options, use `JAVA_OPTS_APPEND` to append options
+# - JAVA_OPTS_APPEND: User specified Java options to be appended to generated options
+# in JAVA_OPTS (example: "-Dsome.property=foo")
+# - JAVA_MAX_MEM_RATIO: Is used when no `-Xmx` option is given in JAVA_OPTS. This is
+# used to calculate a default maximal heap memory based on a containers restriction.
+# If used in a container without any memory constraints for the container then this
+# option has no effect. If there is a memory constraint then `-Xmx` is set to a ratio
+# of the container available memory as set here. The default is `50` which means 50%
+# of the available memory is used as an upper boundary. You can skip this mechanism by
+# setting this value to `0` in which case no `-Xmx` option is added.
+# - JAVA_INITIAL_MEM_RATIO: Is used when no `-Xms` option is given in JAVA_OPTS. This
+# is used to calculate a default initial heap memory based on the maximum heap memory.
+# If used in a container without any memory constraints for the container then this
+# option has no effect. If there is a memory constraint then `-Xms` is set to a ratio
+# of the `-Xmx` memory as set here. The default is `25` which means 25% of the `-Xmx`
+# is used as the initial heap size. You can skip this mechanism by setting this value
+# to `0` in which case no `-Xms` option is added (example: "25")
+# - JAVA_MAX_INITIAL_MEM: Is used when no `-Xms` option is given in JAVA_OPTS.
+# This is used to calculate the maximum value of the initial heap memory. If used in
+# a container without any memory constraints for the container then this option has
+# no effect. If there is a memory constraint then `-Xms` is limited to the value set
+# here. The default is 4096MB which means the calculated value of `-Xms` never will
+# be greater than 4096MB. The value of this variable is expressed in MB (example: "4096")
+# - JAVA_DIAGNOSTICS: Set this to get some diagnostics information to standard output
+# when things are happening. This option, if set to true, will set
+# `-XX:+UnlockDiagnosticVMOptions`. Disabled by default (example: "true").
+# - JAVA_DEBUG: If set remote debugging will be switched on. Disabled by default (example:
+# true").
+# - JAVA_DEBUG_PORT: Port used for remote debugging. Defaults to 5005 (example: "8787").
+# - CONTAINER_CORE_LIMIT: A calculated core limit as described in
+# https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt. (example: "2")
+# - CONTAINER_MAX_MEMORY: Memory limit given to the container (example: "1024").
+# - GC_MIN_HEAP_FREE_RATIO: Minimum percentage of heap free after GC to avoid expansion.
+# (example: "20")
+# - GC_MAX_HEAP_FREE_RATIO: Maximum percentage of heap free after GC to avoid shrinking.
+# (example: "40")
+# - GC_TIME_RATIO: Specifies the ratio of the time spent outside the garbage collection.
+# (example: "4")
+# - GC_ADAPTIVE_SIZE_POLICY_WEIGHT: The weighting given to the current GC time versus
+# previous GC times. (example: "90")
+# - GC_METASPACE_SIZE: The initial metaspace size. (example: "20")
+# - GC_MAX_METASPACE_SIZE: The maximum metaspace size. (example: "100")
+# - GC_CONTAINER_OPTIONS: Specify Java GC to use. The value of this variable should
+# contain the necessary JRE command-line options to specify the required GC, which
+# will override the default of `-XX:+UseParallelGC` (example: -XX:+UseG1GC).
+# - HTTPS_PROXY: The location of the https proxy. (example: "myuser@127.0.0.1:8080")
+# - HTTP_PROXY: The location of the http proxy. (example: "myuser@127.0.0.1:8080")
+# - NO_PROXY: A comma separated lists of hosts, IP addresses or domains that can be
+# accessed directly. (example: "foo.example.com,bar.example.com")
+#
+###
+FROM registry.access.redhat.com/ubi9/openjdk-21:1.21
+
+ENV LANGUAGE='en_US:en'
+
+
+# We make four distinct layers so if there are application changes the library layers can be re-used
+COPY --chown=185 target/quarkus-app/lib/ /deployments/lib/
+COPY --chown=185 target/quarkus-app/*.jar /deployments/
+COPY --chown=185 target/quarkus-app/app/ /deployments/app/
+COPY --chown=185 target/quarkus-app/quarkus/ /deployments/quarkus/
+
+EXPOSE 8080
+USER 185
+ENV JAVA_OPTS_APPEND="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
+ENV JAVA_APP_JAR="/deployments/quarkus-run.jar"
+
+ENTRYPOINT [ "/opt/jboss/container/java/run/run-java.sh" ]
+
diff --git a/examples/quarkus-demo/src/main/docker/Dockerfile.legacy-jar b/examples/quarkus-demo/src/main/docker/Dockerfile.legacy-jar
new file mode 100644
index 00000000..0c8c5762
--- /dev/null
+++ b/examples/quarkus-demo/src/main/docker/Dockerfile.legacy-jar
@@ -0,0 +1,94 @@
+####
+# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode
+#
+# Before building the container image run:
+#
+# ./mvnw package -Dquarkus.package.jar.type=legacy-jar
+#
+# Then, build the image with:
+#
+# docker build -f src/main/docker/Dockerfile.legacy-jar -t quarkus/quarkus-demo-legacy-jar .
+#
+# Then run the container using:
+#
+# docker run -i --rm -p 8080:8080 quarkus/quarkus-demo-legacy-jar
+#
+# If you want to include the debug port into your docker image
+# you will have to expose the debug port (default 5005 being the default) like this : EXPOSE 8080 5005.
+# Additionally you will have to set -e JAVA_DEBUG=true and -e JAVA_DEBUG_PORT=*:5005
+# when running the container
+#
+# Then run the container using :
+#
+# docker run -i --rm -p 8080:8080 quarkus/quarkus-demo-legacy-jar
+#
+# This image uses the `run-java.sh` script to run the application.
+# This scripts computes the command line to execute your Java application, and
+# includes memory/GC tuning.
+# You can configure the behavior using the following environment properties:
+# - JAVA_OPTS: JVM options passed to the `java` command (example: "-verbose:class") - Be aware that this will override
+# the default JVM options, use `JAVA_OPTS_APPEND` to append options
+# - JAVA_OPTS_APPEND: User specified Java options to be appended to generated options
+# in JAVA_OPTS (example: "-Dsome.property=foo")
+# - JAVA_MAX_MEM_RATIO: Is used when no `-Xmx` option is given in JAVA_OPTS. This is
+# used to calculate a default maximal heap memory based on a containers restriction.
+# If used in a container without any memory constraints for the container then this
+# option has no effect. If there is a memory constraint then `-Xmx` is set to a ratio
+# of the container available memory as set here. The default is `50` which means 50%
+# of the available memory is used as an upper boundary. You can skip this mechanism by
+# setting this value to `0` in which case no `-Xmx` option is added.
+# - JAVA_INITIAL_MEM_RATIO: Is used when no `-Xms` option is given in JAVA_OPTS. This
+# is used to calculate a default initial heap memory based on the maximum heap memory.
+# If used in a container without any memory constraints for the container then this
+# option has no effect. If there is a memory constraint then `-Xms` is set to a ratio
+# of the `-Xmx` memory as set here. The default is `25` which means 25% of the `-Xmx`
+# is used as the initial heap size. You can skip this mechanism by setting this value
+# to `0` in which case no `-Xms` option is added (example: "25")
+# - JAVA_MAX_INITIAL_MEM: Is used when no `-Xms` option is given in JAVA_OPTS.
+# This is used to calculate the maximum value of the initial heap memory. If used in
+# a container without any memory constraints for the container then this option has
+# no effect. If there is a memory constraint then `-Xms` is limited to the value set
+# here. The default is 4096MB which means the calculated value of `-Xms` never will
+# be greater than 4096MB. The value of this variable is expressed in MB (example: "4096")
+# - JAVA_DIAGNOSTICS: Set this to get some diagnostics information to standard output
+# when things are happening. This option, if set to true, will set
+# `-XX:+UnlockDiagnosticVMOptions`. Disabled by default (example: "true").
+# - JAVA_DEBUG: If set remote debugging will be switched on. Disabled by default (example:
+# true").
+# - JAVA_DEBUG_PORT: Port used for remote debugging. Defaults to 5005 (example: "8787").
+# - CONTAINER_CORE_LIMIT: A calculated core limit as described in
+# https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt. (example: "2")
+# - CONTAINER_MAX_MEMORY: Memory limit given to the container (example: "1024").
+# - GC_MIN_HEAP_FREE_RATIO: Minimum percentage of heap free after GC to avoid expansion.
+# (example: "20")
+# - GC_MAX_HEAP_FREE_RATIO: Maximum percentage of heap free after GC to avoid shrinking.
+# (example: "40")
+# - GC_TIME_RATIO: Specifies the ratio of the time spent outside the garbage collection.
+# (example: "4")
+# - GC_ADAPTIVE_SIZE_POLICY_WEIGHT: The weighting given to the current GC time versus
+# previous GC times. (example: "90")
+# - GC_METASPACE_SIZE: The initial metaspace size. (example: "20")
+# - GC_MAX_METASPACE_SIZE: The maximum metaspace size. (example: "100")
+# - GC_CONTAINER_OPTIONS: Specify Java GC to use. The value of this variable should
+# contain the necessary JRE command-line options to specify the required GC, which
+# will override the default of `-XX:+UseParallelGC` (example: -XX:+UseG1GC).
+# - HTTPS_PROXY: The location of the https proxy. (example: "myuser@127.0.0.1:8080")
+# - HTTP_PROXY: The location of the http proxy. (example: "myuser@127.0.0.1:8080")
+# - NO_PROXY: A comma separated lists of hosts, IP addresses or domains that can be
+# accessed directly. (example: "foo.example.com,bar.example.com")
+#
+###
+FROM registry.access.redhat.com/ubi9/openjdk-21:1.21
+
+ENV LANGUAGE='en_US:en'
+
+
+COPY target/lib/* /deployments/lib/
+COPY target/*-runner.jar /deployments/quarkus-run.jar
+
+EXPOSE 8080
+USER 185
+ENV JAVA_OPTS_APPEND="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
+ENV JAVA_APP_JAR="/deployments/quarkus-run.jar"
+
+ENTRYPOINT [ "/opt/jboss/container/java/run/run-java.sh" ]
diff --git a/examples/quarkus-demo/src/main/docker/Dockerfile.native b/examples/quarkus-demo/src/main/docker/Dockerfile.native
new file mode 100644
index 00000000..4c12c90d
--- /dev/null
+++ b/examples/quarkus-demo/src/main/docker/Dockerfile.native
@@ -0,0 +1,29 @@
+####
+# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode.
+#
+# Before building the container image run:
+#
+# ./mvnw package -Dnative
+#
+# Then, build the image with:
+#
+# docker build -f src/main/docker/Dockerfile.native -t quarkus/quarkus-demo .
+#
+# Then run the container using:
+#
+# docker run -i --rm -p 8080:8080 quarkus/quarkus-demo
+#
+# The ` registry.access.redhat.com/ubi9/ubi-minimal:9.5` base image is based on UBI 9.
+# To use UBI 8, switch to `quay.io/ubi8/ubi-minimal:8.10`.
+###
+FROM registry.access.redhat.com/ubi9/ubi-minimal:9.5
+WORKDIR /work/
+RUN chown 1001 /work \
+ && chmod "g+rwX" /work \
+ && chown 1001:root /work
+COPY --chown=1001:root --chmod=0755 target/*-runner /work/application
+
+EXPOSE 8080
+USER 1001
+
+ENTRYPOINT ["./application", "-Dquarkus.http.host=0.0.0.0"]
diff --git a/examples/quarkus-demo/src/main/docker/Dockerfile.native-micro b/examples/quarkus-demo/src/main/docker/Dockerfile.native-micro
new file mode 100644
index 00000000..bd1e0f07
--- /dev/null
+++ b/examples/quarkus-demo/src/main/docker/Dockerfile.native-micro
@@ -0,0 +1,32 @@
+####
+# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode.
+# It uses a micro base image, tuned for Quarkus native executables.
+# It reduces the size of the resulting container image.
+# Check https://quarkus.io/guides/quarkus-runtime-base-image for further information about this image.
+#
+# Before building the container image run:
+#
+# ./mvnw package -Dnative
+#
+# Then, build the image with:
+#
+# docker build -f src/main/docker/Dockerfile.native-micro -t quarkus/quarkus-demo .
+#
+# Then run the container using:
+#
+# docker run -i --rm -p 8080:8080 quarkus/quarkus-demo
+#
+# The `quay.io/quarkus/ubi9-quarkus-micro-image:2.0` base image is based on UBI 9.
+# To use UBI 8, switch to `quay.io/quarkus/quarkus-micro-image:2.0`.
+###
+FROM quay.io/quarkus/ubi9-quarkus-micro-image:2.0
+WORKDIR /work/
+RUN chown 1001 /work \
+ && chmod "g+rwX" /work \
+ && chown 1001:root /work
+COPY --chown=1001:root --chmod=0755 target/*-runner /work/application
+
+EXPOSE 8080
+USER 1001
+
+ENTRYPOINT ["./application", "-Dquarkus.http.host=0.0.0.0"]
diff --git a/examples/quarkus-demo/src/main/java/org/acme/GreetingResource.java b/examples/quarkus-demo/src/main/java/org/acme/GreetingResource.java
new file mode 100644
index 00000000..244f2942
--- /dev/null
+++ b/examples/quarkus-demo/src/main/java/org/acme/GreetingResource.java
@@ -0,0 +1,16 @@
+package org.acme;
+
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
+
+@Path("/hello")
+public class GreetingResource {
+
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ public String hello() {
+ return "Hello from Quarkus REST";
+ }
+}
diff --git a/examples/quarkus-demo/src/main/resources/application.properties b/examples/quarkus-demo/src/main/resources/application.properties
new file mode 100644
index 00000000..e69de29b
diff --git a/examples/quarkus-demo/src/test/java/org/acme/GreetingResourceIT.java b/examples/quarkus-demo/src/test/java/org/acme/GreetingResourceIT.java
new file mode 100644
index 00000000..cfa9d1b1
--- /dev/null
+++ b/examples/quarkus-demo/src/test/java/org/acme/GreetingResourceIT.java
@@ -0,0 +1,8 @@
+package org.acme;
+
+import io.quarkus.test.junit.QuarkusIntegrationTest;
+
+@QuarkusIntegrationTest
+class GreetingResourceIT extends GreetingResourceTest {
+ // Execute the same tests but in packaged mode.
+}
diff --git a/examples/quarkus-demo/src/test/java/org/acme/GreetingResourceTest.java b/examples/quarkus-demo/src/test/java/org/acme/GreetingResourceTest.java
new file mode 100644
index 00000000..18332e4c
--- /dev/null
+++ b/examples/quarkus-demo/src/test/java/org/acme/GreetingResourceTest.java
@@ -0,0 +1,20 @@
+package org.acme;
+
+import io.quarkus.test.junit.QuarkusTest;
+import org.junit.jupiter.api.Test;
+
+import static io.restassured.RestAssured.given;
+import static org.hamcrest.CoreMatchers.is;
+
+@QuarkusTest
+class GreetingResourceTest {
+ @Test
+ void testHelloEndpoint() {
+ given()
+ .when().get("/hello")
+ .then()
+ .statusCode(200)
+ .body(is("Hello from Quarkus REST"));
+ }
+
+}
\ No newline at end of file
diff --git a/examples/spring-boot-demo/implementation/run-with-profiler.sh b/examples/spring-boot-demo/implementation/run-with-profiler.sh
new file mode 100644
index 00000000..533283d2
--- /dev/null
+++ b/examples/spring-boot-demo/implementation/run-with-profiler.sh
@@ -0,0 +1,341 @@
+#!/bin/bash
+
+# Java Application Runner with Async-Profiler Support
+# This script runs Spring Boot or Quarkus applications with JVM flags optimized for async-profiler
+
+set -e
+
+# Default values
+PROFILE_MODE="cpu"
+APP_JAR=""
+APP_CLASS="info.jab.ms.MainApplication"
+HEAP_SIZE="512m"
+PROFILE_NAME="default"
+FRAMEWORK="auto"
+
+# Colors for output
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+BLUE='\033[0;34m'
+NC='\033[0m' # No Color
+
+# Function to print colored output
+log_info() {
+ echo -e "${BLUE}[INFO]${NC} $1"
+}
+
+log_warn() {
+ echo -e "${YELLOW}[WARN]${NC} $1"
+}
+
+log_error() {
+ echo -e "${RED}[ERROR]${NC} $1"
+}
+
+log_success() {
+ echo -e "${GREEN}[SUCCESS]${NC} $1"
+}
+
+# Function to show usage
+show_usage() {
+ cat << EOF
+Usage: $0 [OPTIONS]
+
+Run Spring Boot or Quarkus application with async-profiler support
+
+OPTIONS:
+ -m, --mode MODE Profiling mode: cpu, alloc, wall, lock (default: cpu)
+ -f, --framework FRAMEWORK Framework: springboot, quarkus, auto (default: auto)
+ -j, --jar PATH Path to application JAR file
+ -c, --class CLASS Main class to run (default: info.jab.ms.MainApplication)
+ -h, --heap SIZE Heap size (default: 512m)
+ -p, --profile PROFILE Profile to activate (default: default)
+ --help Show this help message
+
+FRAMEWORK DETECTION:
+ auto Automatically detect framework from pom.xml or JAR naming
+ springboot Force Spring Boot mode
+ quarkus Force Quarkus mode
+
+EXAMPLES:
+ # Auto-detect framework and run with CPU profiling
+ $0 -m cpu
+
+ # Force Spring Boot with memory allocation profiling
+ $0 -f springboot -m alloc
+
+ # Force Quarkus with custom heap size and profile
+ $0 -f quarkus -h 1g -p dev
+
+ # Run with wall-clock profiling
+ $0 -m wall
+
+EOF
+}
+
+# Parse command line arguments
+while [[ $# -gt 0 ]]; do
+ case $1 in
+ -m|--mode)
+ PROFILE_MODE="$2"
+ shift 2
+ ;;
+ -f|--framework)
+ FRAMEWORK="$2"
+ shift 2
+ ;;
+ -j|--jar)
+ APP_JAR="$2"
+ shift 2
+ ;;
+ -c|--class)
+ APP_CLASS="$2"
+ shift 2
+ ;;
+ -h|--heap)
+ HEAP_SIZE="$2"
+ shift 2
+ ;;
+ -p|--profile)
+ PROFILE_NAME="$2"
+ shift 2
+ ;;
+ --help)
+ show_usage
+ exit 0
+ ;;
+ *)
+ log_error "Unknown option: $1"
+ show_usage
+ exit 1
+ ;;
+ esac
+done
+
+# Validate profiling mode
+case $PROFILE_MODE in
+ cpu|alloc|wall|lock)
+ ;;
+ *)
+ log_error "Invalid profiling mode: $PROFILE_MODE. Use: cpu, alloc, wall, lock"
+ exit 1
+ ;;
+esac
+
+# Validate framework
+case $FRAMEWORK in
+ auto|springboot|quarkus)
+ ;;
+ *)
+ log_error "Invalid framework: $FRAMEWORK. Use: auto, springboot, quarkus"
+ exit 1
+ ;;
+esac
+
+# Function to detect framework
+detect_framework() {
+ if [[ "$FRAMEWORK" != "auto" ]]; then
+ return 0
+ fi
+
+ # Check pom.xml for framework indicators
+ if [[ -f "pom.xml" ]]; then
+ if grep -q "spring-boot-starter" pom.xml; then
+ FRAMEWORK="springboot"
+ log_info "Detected Spring Boot from pom.xml"
+ elif grep -q "quarkus-universe-bom\|quarkus-bom" pom.xml; then
+ FRAMEWORK="quarkus"
+ log_info "Detected Quarkus from pom.xml"
+ fi
+ fi
+
+ # Check for JAR files if framework still not detected
+ if [[ "$FRAMEWORK" == "auto" ]]; then
+ if [[ -n "$APP_JAR" ]]; then
+ if [[ "$APP_JAR" == *"spring-boot"* ]]; then
+ FRAMEWORK="springboot"
+ log_info "Detected Spring Boot from JAR name"
+ elif [[ "$APP_JAR" == *"quarkus"* ]] || [[ "$APP_JAR" == *"runner"* ]]; then
+ FRAMEWORK="quarkus"
+ log_info "Detected Quarkus from JAR name"
+ fi
+ else
+ # Check for JAR files in target directory
+ if ls target/*-runner.jar >/dev/null 2>&1; then
+ FRAMEWORK="quarkus"
+ log_info "Detected Quarkus from runner JAR"
+ elif ls target/*spring-boot*.jar >/dev/null 2>&1; then
+ FRAMEWORK="springboot"
+ log_info "Detected Spring Boot from JAR files"
+ fi
+ fi
+ fi
+
+ # Default to Spring Boot if still not detected
+ if [[ "$FRAMEWORK" == "auto" ]]; then
+ FRAMEWORK="springboot"
+ log_warn "Could not detect framework, defaulting to Spring Boot"
+ fi
+}
+
+# Function to set framework-specific JAR if not provided
+set_default_jar() {
+ if [[ -z "$APP_JAR" ]]; then
+ case $FRAMEWORK in
+ springboot)
+ # Look for Spring Boot JAR
+ if ls target/*spring-boot*.jar >/dev/null 2>&1; then
+ APP_JAR=$(ls target/*spring-boot*.jar | head -1)
+ else
+ # Fallback to common naming pattern
+ PROJECT_NAME=$(basename "$(pwd)")
+ APP_JAR="target/${PROJECT_NAME}-1.0-SNAPSHOT.jar"
+ fi
+ ;;
+ quarkus)
+ # Look for Quarkus runner JAR
+ if ls target/*-runner.jar >/dev/null 2>&1; then
+ APP_JAR=$(ls target/*-runner.jar | head -1)
+ else
+ # Fallback to common naming pattern
+ PROJECT_NAME=$(basename "$(pwd)")
+ APP_JAR="target/${PROJECT_NAME}-1.0-SNAPSHOT-runner.jar"
+ fi
+ ;;
+ esac
+ log_info "Using default JAR: $APP_JAR"
+ fi
+}
+
+# Detect framework and set defaults
+detect_framework
+set_default_jar
+
+# Generate timestamp for output files
+TIMESTAMP=$(date +"%Y%m%d-%H%M%S")
+
+log_info "Starting $FRAMEWORK application"
+log_info "Profile mode: $PROFILE_MODE"
+log_info "Framework: $FRAMEWORK"
+log_info "Profile: $PROFILE_NAME"
+
+# JVM flags for optimal profiling with async-profiler
+JVM_FLAGS=(
+ # Memory settings
+ "-Xms$HEAP_SIZE"
+ "-Xmx$HEAP_SIZE"
+
+ # Profiling optimization flags
+ "-XX:+UnlockDiagnosticVMOptions"
+ "-XX:+DebugNonSafepoints"
+ "-XX:+PreserveFramePointer"
+
+ # JFR settings (useful for some profiling modes)
+ "-XX:+FlightRecorder"
+ "-XX:StartFlightRecording=filename=flight-recording-${TIMESTAMP}.jfr"
+
+ # GC logging for memory leak analysis
+ "-Xlog:gc*:gc-${TIMESTAMP}.log:time,tags"
+
+ # Security settings for profiler attachment
+ "-Djdk.attach.allowAttachSelf=true"
+
+ # Optional: Disable C2 compiler for more accurate profiling (uncomment if needed)
+ # "-XX:TieredStopAtLevel=1"
+)
+
+# Framework-specific arguments
+get_app_args() {
+ case $FRAMEWORK in
+ springboot)
+ APP_ARGS=(
+ "--spring.profiles.active=$PROFILE_NAME"
+ "--logging.level.info.jab.ms=DEBUG"
+ "--server.port=8080"
+ )
+ ;;
+ quarkus)
+ APP_ARGS=(
+ "-Dquarkus.profile=$PROFILE_NAME"
+ "-Dquarkus.log.category.\"info.jab.ms\".level=DEBUG"
+ "-Dquarkus.http.port=8080"
+ )
+ ;;
+ esac
+}
+
+# Get framework-specific arguments
+get_app_args
+
+# Function to run with Maven
+run_with_maven() {
+ log_info "Running with Maven..."
+ export JAVA_TOOL_OPTIONS="${JVM_FLAGS[*]}"
+
+ case $FRAMEWORK in
+ springboot)
+ # Start Spring Boot application
+ mvn spring-boot:run \
+ -Dspring-boot.run.profiles="$PROFILE_NAME" \
+ -Dspring-boot.run.arguments="$(IFS=' '; echo "${APP_ARGS[*]}")"
+ ;;
+ quarkus)
+ # Start Quarkus application in dev mode
+ mvn quarkus:dev \
+ -Dquarkus.args="$(IFS=' '; echo "${APP_ARGS[*]}")"
+ ;;
+ esac
+}
+
+# Function to run with JAR
+run_with_jar() {
+ if [[ ! -f "$APP_JAR" ]]; then
+ log_error "JAR file not found: $APP_JAR"
+ log_info "Building the application first..."
+ case $FRAMEWORK in
+ springboot)
+ mvn clean package -DskipTests
+ ;;
+ quarkus)
+ mvn clean package -DskipTests
+ ;;
+ esac
+ fi
+
+ if [[ ! -f "$APP_JAR" ]]; then
+ log_error "Failed to build or find JAR file: $APP_JAR"
+ exit 1
+ fi
+
+ log_info "Running JAR: $APP_JAR"
+
+ # Start the application
+ java "${JVM_FLAGS[@]}" -jar "$APP_JAR" "${APP_ARGS[@]}"
+}
+
+# Function to run with class
+run_with_class() {
+ log_info "Running main class: $APP_CLASS"
+
+ # Start the application
+ java "${JVM_FLAGS[@]}" -cp "target/classes:$(mvn dependency:build-classpath -Dmdep.outputFile=/dev/stdout -q)" "$APP_CLASS" "${APP_ARGS[@]}"
+}
+
+# Main execution
+log_info "JVM Flags: ${JVM_FLAGS[*]}"
+
+# Determine how to run the application
+if [[ -f "pom.xml" ]] && command -v mvn >/dev/null 2>&1; then
+ if [[ -f "$APP_JAR" ]]; then
+ run_with_jar
+ else
+ run_with_maven
+ fi
+elif [[ -f "$APP_JAR" ]]; then
+ run_with_jar
+else
+ run_with_class
+fi
+
+log_success "Application completed!"
\ No newline at end of file
diff --git a/examples/spring-boot-memory-leak-demo/run-with-profiler.sh b/examples/spring-boot-memory-leak-demo/run-with-profiler.sh
index f634a672..533283d2 100755
--- a/examples/spring-boot-memory-leak-demo/run-with-profiler.sh
+++ b/examples/spring-boot-memory-leak-demo/run-with-profiler.sh
@@ -1,16 +1,17 @@
#!/bin/bash
-# Spring Boot Application Runner with Async-Profiler Support
-# This script runs the Spring Boot application with JVM flags optimized for async-profiler
+# Java Application Runner with Async-Profiler Support
+# This script runs Spring Boot or Quarkus applications with JVM flags optimized for async-profiler
set -e
# Default values
PROFILE_MODE="cpu"
-APP_JAR="target/spring-boot-memory-leak-demo-1.0-SNAPSHOT.jar"
+APP_JAR=""
APP_CLASS="info.jab.ms.MainApplication"
HEAP_SIZE="512m"
-SPRING_PROFILE="default"
+PROFILE_NAME="default"
+FRAMEWORK="auto"
# Colors for output
RED='\033[0;31m'
@@ -41,25 +42,31 @@ show_usage() {
cat << EOF
Usage: $0 [OPTIONS]
-Run Spring Boot application with async-profiler support
+Run Spring Boot or Quarkus application with async-profiler support
OPTIONS:
-m, --mode MODE Profiling mode: cpu, alloc, wall, lock (default: cpu)
+ -f, --framework FRAMEWORK Framework: springboot, quarkus, auto (default: auto)
-j, --jar PATH Path to application JAR file
-c, --class CLASS Main class to run (default: info.jab.ms.MainApplication)
-h, --heap SIZE Heap size (default: 512m)
- -s, --spring-profile Spring profile to activate (default: default)
+ -p, --profile PROFILE Profile to activate (default: default)
--help Show this help message
+FRAMEWORK DETECTION:
+ auto Automatically detect framework from pom.xml or JAR naming
+ springboot Force Spring Boot mode
+ quarkus Force Quarkus mode
+
EXAMPLES:
- # Run with CPU profiling mode
+ # Auto-detect framework and run with CPU profiling
$0 -m cpu
- # Run with memory allocation profiling
- $0 -m alloc
+ # Force Spring Boot with memory allocation profiling
+ $0 -f springboot -m alloc
- # Run with custom heap size and Spring profile
- $0 -h 1g -s dev
+ # Force Quarkus with custom heap size and profile
+ $0 -f quarkus -h 1g -p dev
# Run with wall-clock profiling
$0 -m wall
@@ -74,6 +81,10 @@ while [[ $# -gt 0 ]]; do
PROFILE_MODE="$2"
shift 2
;;
+ -f|--framework)
+ FRAMEWORK="$2"
+ shift 2
+ ;;
-j|--jar)
APP_JAR="$2"
shift 2
@@ -86,8 +97,8 @@ while [[ $# -gt 0 ]]; do
HEAP_SIZE="$2"
shift 2
;;
- -s|--spring-profile)
- SPRING_PROFILE="$2"
+ -p|--profile)
+ PROFILE_NAME="$2"
shift 2
;;
--help)
@@ -112,12 +123,102 @@ case $PROFILE_MODE in
;;
esac
+# Validate framework
+case $FRAMEWORK in
+ auto|springboot|quarkus)
+ ;;
+ *)
+ log_error "Invalid framework: $FRAMEWORK. Use: auto, springboot, quarkus"
+ exit 1
+ ;;
+esac
+
+# Function to detect framework
+detect_framework() {
+ if [[ "$FRAMEWORK" != "auto" ]]; then
+ return 0
+ fi
+
+ # Check pom.xml for framework indicators
+ if [[ -f "pom.xml" ]]; then
+ if grep -q "spring-boot-starter" pom.xml; then
+ FRAMEWORK="springboot"
+ log_info "Detected Spring Boot from pom.xml"
+ elif grep -q "quarkus-universe-bom\|quarkus-bom" pom.xml; then
+ FRAMEWORK="quarkus"
+ log_info "Detected Quarkus from pom.xml"
+ fi
+ fi
+
+ # Check for JAR files if framework still not detected
+ if [[ "$FRAMEWORK" == "auto" ]]; then
+ if [[ -n "$APP_JAR" ]]; then
+ if [[ "$APP_JAR" == *"spring-boot"* ]]; then
+ FRAMEWORK="springboot"
+ log_info "Detected Spring Boot from JAR name"
+ elif [[ "$APP_JAR" == *"quarkus"* ]] || [[ "$APP_JAR" == *"runner"* ]]; then
+ FRAMEWORK="quarkus"
+ log_info "Detected Quarkus from JAR name"
+ fi
+ else
+ # Check for JAR files in target directory
+ if ls target/*-runner.jar >/dev/null 2>&1; then
+ FRAMEWORK="quarkus"
+ log_info "Detected Quarkus from runner JAR"
+ elif ls target/*spring-boot*.jar >/dev/null 2>&1; then
+ FRAMEWORK="springboot"
+ log_info "Detected Spring Boot from JAR files"
+ fi
+ fi
+ fi
+
+ # Default to Spring Boot if still not detected
+ if [[ "$FRAMEWORK" == "auto" ]]; then
+ FRAMEWORK="springboot"
+ log_warn "Could not detect framework, defaulting to Spring Boot"
+ fi
+}
+
+# Function to set framework-specific JAR if not provided
+set_default_jar() {
+ if [[ -z "$APP_JAR" ]]; then
+ case $FRAMEWORK in
+ springboot)
+ # Look for Spring Boot JAR
+ if ls target/*spring-boot*.jar >/dev/null 2>&1; then
+ APP_JAR=$(ls target/*spring-boot*.jar | head -1)
+ else
+ # Fallback to common naming pattern
+ PROJECT_NAME=$(basename "$(pwd)")
+ APP_JAR="target/${PROJECT_NAME}-1.0-SNAPSHOT.jar"
+ fi
+ ;;
+ quarkus)
+ # Look for Quarkus runner JAR
+ if ls target/*-runner.jar >/dev/null 2>&1; then
+ APP_JAR=$(ls target/*-runner.jar | head -1)
+ else
+ # Fallback to common naming pattern
+ PROJECT_NAME=$(basename "$(pwd)")
+ APP_JAR="target/${PROJECT_NAME}-1.0-SNAPSHOT-runner.jar"
+ fi
+ ;;
+ esac
+ log_info "Using default JAR: $APP_JAR"
+ fi
+}
+
+# Detect framework and set defaults
+detect_framework
+set_default_jar
+
# Generate timestamp for output files
TIMESTAMP=$(date +"%Y%m%d-%H%M%S")
-log_info "Starting Spring Boot application"
+log_info "Starting $FRAMEWORK application"
log_info "Profile mode: $PROFILE_MODE"
-log_info "Spring profile: $SPRING_PROFILE"
+log_info "Framework: $FRAMEWORK"
+log_info "Profile: $PROFILE_NAME"
# JVM flags for optimal profiling with async-profiler
JVM_FLAGS=(
@@ -144,22 +245,47 @@ JVM_FLAGS=(
# "-XX:TieredStopAtLevel=1"
)
-# Spring Boot specific arguments
-SPRING_ARGS=(
- "--spring.profiles.active=$SPRING_PROFILE"
- "--logging.level.info.jab.ms=DEBUG"
- "--server.port=8080"
-)
+# Framework-specific arguments
+get_app_args() {
+ case $FRAMEWORK in
+ springboot)
+ APP_ARGS=(
+ "--spring.profiles.active=$PROFILE_NAME"
+ "--logging.level.info.jab.ms=DEBUG"
+ "--server.port=8080"
+ )
+ ;;
+ quarkus)
+ APP_ARGS=(
+ "-Dquarkus.profile=$PROFILE_NAME"
+ "-Dquarkus.log.category.\"info.jab.ms\".level=DEBUG"
+ "-Dquarkus.http.port=8080"
+ )
+ ;;
+ esac
+}
+
+# Get framework-specific arguments
+get_app_args
# Function to run with Maven
run_with_maven() {
log_info "Running with Maven..."
export JAVA_TOOL_OPTIONS="${JVM_FLAGS[*]}"
- # Start the application
- mvn spring-boot:run \
- -Dspring-boot.run.profiles="$SPRING_PROFILE" \
- -Dspring-boot.run.arguments="$(IFS=' '; echo "${SPRING_ARGS[*]}")"
+ case $FRAMEWORK in
+ springboot)
+ # Start Spring Boot application
+ mvn spring-boot:run \
+ -Dspring-boot.run.profiles="$PROFILE_NAME" \
+ -Dspring-boot.run.arguments="$(IFS=' '; echo "${APP_ARGS[*]}")"
+ ;;
+ quarkus)
+ # Start Quarkus application in dev mode
+ mvn quarkus:dev \
+ -Dquarkus.args="$(IFS=' '; echo "${APP_ARGS[*]}")"
+ ;;
+ esac
}
# Function to run with JAR
@@ -167,7 +293,14 @@ run_with_jar() {
if [[ ! -f "$APP_JAR" ]]; then
log_error "JAR file not found: $APP_JAR"
log_info "Building the application first..."
- mvn clean package -DskipTests
+ case $FRAMEWORK in
+ springboot)
+ mvn clean package -DskipTests
+ ;;
+ quarkus)
+ mvn clean package -DskipTests
+ ;;
+ esac
fi
if [[ ! -f "$APP_JAR" ]]; then
@@ -178,7 +311,7 @@ run_with_jar() {
log_info "Running JAR: $APP_JAR"
# Start the application
- java "${JVM_FLAGS[@]}" -jar "$APP_JAR" "${SPRING_ARGS[@]}"
+ java "${JVM_FLAGS[@]}" -jar "$APP_JAR" "${APP_ARGS[@]}"
}
# Function to run with class
@@ -186,7 +319,7 @@ run_with_class() {
log_info "Running main class: $APP_CLASS"
# Start the application
- java "${JVM_FLAGS[@]}" -cp "target/classes:$(mvn dependency:build-classpath -Dmdep.outputFile=/dev/stdout -q)" "$APP_CLASS" "${SPRING_ARGS[@]}"
+ java "${JVM_FLAGS[@]}" -cp "target/classes:$(mvn dependency:build-classpath -Dmdep.outputFile=/dev/stdout -q)" "$APP_CLASS" "${APP_ARGS[@]}"
}
# Main execution
diff --git a/examples/spring-boot-performance-bottleneck-demo/run-with-profiler.sh b/examples/spring-boot-performance-bottleneck-demo/run-with-profiler.sh
index f634a672..18c9a33b 100755
--- a/examples/spring-boot-performance-bottleneck-demo/run-with-profiler.sh
+++ b/examples/spring-boot-performance-bottleneck-demo/run-with-profiler.sh
@@ -1,16 +1,17 @@
#!/bin/bash
-# Spring Boot Application Runner with Async-Profiler Support
-# This script runs the Spring Boot application with JVM flags optimized for async-profiler
+# Java Application Runner with Async-Profiler Support
+# This script runs Spring Boot or Quarkus applications with JVM flags optimized for async-profiler
set -e
# Default values
PROFILE_MODE="cpu"
-APP_JAR="target/spring-boot-memory-leak-demo-1.0-SNAPSHOT.jar"
-APP_CLASS="info.jab.ms.MainApplication"
+APP_JAR=""
+APP_CLASS="info.jab.info.MainApplication"
HEAP_SIZE="512m"
-SPRING_PROFILE="default"
+PROFILE_NAME="default"
+FRAMEWORK="auto"
# Colors for output
RED='\033[0;31m'
@@ -41,25 +42,31 @@ show_usage() {
cat << EOF
Usage: $0 [OPTIONS]
-Run Spring Boot application with async-profiler support
+Run Spring Boot or Quarkus application with async-profiler support
OPTIONS:
-m, --mode MODE Profiling mode: cpu, alloc, wall, lock (default: cpu)
+ -f, --framework FRAMEWORK Framework: springboot, quarkus, auto (default: auto)
-j, --jar PATH Path to application JAR file
- -c, --class CLASS Main class to run (default: info.jab.ms.MainApplication)
+ -c, --class CLASS Main class to run (default: info.jab.info.MainApplication)
-h, --heap SIZE Heap size (default: 512m)
- -s, --spring-profile Spring profile to activate (default: default)
+ -p, --profile PROFILE Profile to activate (default: default)
--help Show this help message
+FRAMEWORK DETECTION:
+ auto Automatically detect framework from pom.xml or JAR naming
+ springboot Force Spring Boot mode
+ quarkus Force Quarkus mode
+
EXAMPLES:
- # Run with CPU profiling mode
+ # Auto-detect framework and run with CPU profiling
$0 -m cpu
- # Run with memory allocation profiling
- $0 -m alloc
+ # Force Spring Boot with memory allocation profiling
+ $0 -f springboot -m alloc
- # Run with custom heap size and Spring profile
- $0 -h 1g -s dev
+ # Force Quarkus with custom heap size and profile
+ $0 -f quarkus -h 1g -p dev
# Run with wall-clock profiling
$0 -m wall
@@ -74,6 +81,10 @@ while [[ $# -gt 0 ]]; do
PROFILE_MODE="$2"
shift 2
;;
+ -f|--framework)
+ FRAMEWORK="$2"
+ shift 2
+ ;;
-j|--jar)
APP_JAR="$2"
shift 2
@@ -86,8 +97,8 @@ while [[ $# -gt 0 ]]; do
HEAP_SIZE="$2"
shift 2
;;
- -s|--spring-profile)
- SPRING_PROFILE="$2"
+ -p|--profile)
+ PROFILE_NAME="$2"
shift 2
;;
--help)
@@ -112,12 +123,102 @@ case $PROFILE_MODE in
;;
esac
+# Validate framework
+case $FRAMEWORK in
+ auto|springboot|quarkus)
+ ;;
+ *)
+ log_error "Invalid framework: $FRAMEWORK. Use: auto, springboot, quarkus"
+ exit 1
+ ;;
+esac
+
+# Function to detect framework
+detect_framework() {
+ if [[ "$FRAMEWORK" != "auto" ]]; then
+ return 0
+ fi
+
+ # Check pom.xml for framework indicators
+ if [[ -f "pom.xml" ]]; then
+ if grep -q "spring-boot-starter" pom.xml; then
+ FRAMEWORK="springboot"
+ log_info "Detected Spring Boot from pom.xml"
+ elif grep -q "quarkus-universe-bom\|quarkus-bom" pom.xml; then
+ FRAMEWORK="quarkus"
+ log_info "Detected Quarkus from pom.xml"
+ fi
+ fi
+
+ # Check for JAR files if framework still not detected
+ if [[ "$FRAMEWORK" == "auto" ]]; then
+ if [[ -n "$APP_JAR" ]]; then
+ if [[ "$APP_JAR" == *"spring-boot"* ]]; then
+ FRAMEWORK="springboot"
+ log_info "Detected Spring Boot from JAR name"
+ elif [[ "$APP_JAR" == *"quarkus"* ]] || [[ "$APP_JAR" == *"runner"* ]]; then
+ FRAMEWORK="quarkus"
+ log_info "Detected Quarkus from JAR name"
+ fi
+ else
+ # Check for JAR files in target directory
+ if ls target/*-runner.jar >/dev/null 2>&1; then
+ FRAMEWORK="quarkus"
+ log_info "Detected Quarkus from runner JAR"
+ elif ls target/*spring-boot*.jar >/dev/null 2>&1; then
+ FRAMEWORK="springboot"
+ log_info "Detected Spring Boot from JAR files"
+ fi
+ fi
+ fi
+
+ # Default to Spring Boot if still not detected
+ if [[ "$FRAMEWORK" == "auto" ]]; then
+ FRAMEWORK="springboot"
+ log_warn "Could not detect framework, defaulting to Spring Boot"
+ fi
+}
+
+# Function to set framework-specific JAR if not provided
+set_default_jar() {
+ if [[ -z "$APP_JAR" ]]; then
+ case $FRAMEWORK in
+ springboot)
+ # Look for Spring Boot JAR
+ if ls target/*spring-boot*.jar >/dev/null 2>&1; then
+ APP_JAR=$(ls target/*spring-boot*.jar | head -1)
+ else
+ # Fallback to common naming pattern
+ PROJECT_NAME=$(basename "$(pwd)")
+ APP_JAR="target/${PROJECT_NAME}-1.0-SNAPSHOT.jar"
+ fi
+ ;;
+ quarkus)
+ # Look for Quarkus runner JAR
+ if ls target/*-runner.jar >/dev/null 2>&1; then
+ APP_JAR=$(ls target/*-runner.jar | head -1)
+ else
+ # Fallback to common naming pattern
+ PROJECT_NAME=$(basename "$(pwd)")
+ APP_JAR="target/${PROJECT_NAME}-1.0-SNAPSHOT-runner.jar"
+ fi
+ ;;
+ esac
+ log_info "Using default JAR: $APP_JAR"
+ fi
+}
+
+# Detect framework and set defaults
+detect_framework
+set_default_jar
+
# Generate timestamp for output files
TIMESTAMP=$(date +"%Y%m%d-%H%M%S")
-log_info "Starting Spring Boot application"
+log_info "Starting $FRAMEWORK application"
log_info "Profile mode: $PROFILE_MODE"
-log_info "Spring profile: $SPRING_PROFILE"
+log_info "Framework: $FRAMEWORK"
+log_info "Profile: $PROFILE_NAME"
# JVM flags for optimal profiling with async-profiler
JVM_FLAGS=(
@@ -144,22 +245,47 @@ JVM_FLAGS=(
# "-XX:TieredStopAtLevel=1"
)
-# Spring Boot specific arguments
-SPRING_ARGS=(
- "--spring.profiles.active=$SPRING_PROFILE"
- "--logging.level.info.jab.ms=DEBUG"
- "--server.port=8080"
-)
+# Framework-specific arguments
+get_app_args() {
+ case $FRAMEWORK in
+ springboot)
+ APP_ARGS=(
+ "--spring.profiles.active=$PROFILE_NAME"
+ "--logging.level.info.jab.info=DEBUG"
+ "--server.port=8080"
+ )
+ ;;
+ quarkus)
+ APP_ARGS=(
+ "-Dquarkus.profile=$PROFILE_NAME"
+ "-Dquarkus.log.category.\"info.jab.info\".level=DEBUG"
+ "-Dquarkus.http.port=8080"
+ )
+ ;;
+ esac
+}
+
+# Get framework-specific arguments
+get_app_args
# Function to run with Maven
run_with_maven() {
log_info "Running with Maven..."
export JAVA_TOOL_OPTIONS="${JVM_FLAGS[*]}"
- # Start the application
- mvn spring-boot:run \
- -Dspring-boot.run.profiles="$SPRING_PROFILE" \
- -Dspring-boot.run.arguments="$(IFS=' '; echo "${SPRING_ARGS[*]}")"
+ case $FRAMEWORK in
+ springboot)
+ # Start Spring Boot application
+ mvn spring-boot:run \
+ -Dspring-boot.run.profiles="$PROFILE_NAME" \
+ -Dspring-boot.run.arguments="$(IFS=' '; echo "${APP_ARGS[*]}")"
+ ;;
+ quarkus)
+ # Start Quarkus application in dev mode
+ mvn quarkus:dev \
+ -Dquarkus.args="$(IFS=' '; echo "${APP_ARGS[*]}")"
+ ;;
+ esac
}
# Function to run with JAR
@@ -167,7 +293,14 @@ run_with_jar() {
if [[ ! -f "$APP_JAR" ]]; then
log_error "JAR file not found: $APP_JAR"
log_info "Building the application first..."
- mvn clean package -DskipTests
+ case $FRAMEWORK in
+ springboot)
+ mvn clean package -DskipTests
+ ;;
+ quarkus)
+ mvn clean package -DskipTests
+ ;;
+ esac
fi
if [[ ! -f "$APP_JAR" ]]; then
@@ -178,7 +311,7 @@ run_with_jar() {
log_info "Running JAR: $APP_JAR"
# Start the application
- java "${JVM_FLAGS[@]}" -jar "$APP_JAR" "${SPRING_ARGS[@]}"
+ java "${JVM_FLAGS[@]}" -jar "$APP_JAR" "${APP_ARGS[@]}"
}
# Function to run with class
@@ -186,7 +319,7 @@ run_with_class() {
log_info "Running main class: $APP_CLASS"
# Start the application
- java "${JVM_FLAGS[@]}" -cp "target/classes:$(mvn dependency:build-classpath -Dmdep.outputFile=/dev/stdout -q)" "$APP_CLASS" "${SPRING_ARGS[@]}"
+ java "${JVM_FLAGS[@]}" -cp "target/classes:$(mvn dependency:build-classpath -Dmdep.outputFile=/dev/stdout -q)" "$APP_CLASS" "${APP_ARGS[@]}"
}
# Main execution