From 2db38c0387306138bdf7442d3dae2f7c8d0bc562 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 10 Sep 2025 20:41:17 +0000
Subject: [PATCH 1/4] Initial plan
From 45244ab7bea7731ea654df578914ae89cf72add9 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 10 Sep 2025 20:45:44 +0000
Subject: [PATCH 2/4] Initial assessment and plan for Azure SQL Managed
Identity improvements
Co-authored-by: richposada <454664+richposada@users.noreply.github.com>
---
mi-sql-public-demo/dependency-reduced-pom.xml | 56 +++++++++++++++++++
1 file changed, 56 insertions(+)
create mode 100644 mi-sql-public-demo/dependency-reduced-pom.xml
diff --git a/mi-sql-public-demo/dependency-reduced-pom.xml b/mi-sql-public-demo/dependency-reduced-pom.xml
new file mode 100644
index 0000000..9a8898f
--- /dev/null
+++ b/mi-sql-public-demo/dependency-reduced-pom.xml
@@ -0,0 +1,56 @@
+
+
+ 4.0.0
+ com.example
+ demo
+ 1.0-SNAPSHOT
+
+
+
+ maven-shade-plugin
+ 3.2.4
+
+
+ package
+
+ shade
+
+
+
+
+ com.example.MainSQL
+
+
+
+
+ *:*
+
+ META-INF/*.SF
+ META-INF/*.DSA
+ META-INF/*.RSA
+
+
+
+
+
+
+
+
+
+
+
+
+ com.azure.spring
+ spring-cloud-azure-dependencies
+ 5.22.0
+ pom
+ import
+
+
+
+
+ 17
+ 17
+ 17
+
+
From b35700435f815cf8db48caa5315767b698a91ec3 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 10 Sep 2025 20:50:19 +0000
Subject: [PATCH 3/4] Enhanced Azure SQL Managed Identity implementation with
improved error handling, documentation, and validation
Co-authored-by: richposada <454664+richposada@users.noreply.github.com>
---
mi-sql-public-demo/.gitignore | 29 +++
mi-sql-public-demo/README.md | 204 +++++++++++++++++-
mi-sql-public-demo/pom.xml | 3 +-
.../src/main/java/com/example/MainSQL.java | 147 +++++++++++--
.../src/main/resources/application.properties | 37 +++-
5 files changed, 395 insertions(+), 25 deletions(-)
create mode 100644 mi-sql-public-demo/.gitignore
diff --git a/mi-sql-public-demo/.gitignore b/mi-sql-public-demo/.gitignore
new file mode 100644
index 0000000..d17dbb9
--- /dev/null
+++ b/mi-sql-public-demo/.gitignore
@@ -0,0 +1,29 @@
+# Maven
+target/
+pom.xml.tag
+pom.xml.releaseBackup
+pom.xml.versionsBackup
+pom.xml.next
+release.properties
+dependency-reduced-pom.xml
+buildNumber.properties
+.mvn/timing.properties
+.mvn/wrapper/maven-wrapper.jar
+
+# IDE
+.idea/
+.vscode/
+*.swp
+*.swo
+
+# OS
+.DS_Store
+Thumbs.db
+
+# Logs
+*.log
+logs/
+
+# Application specific
+application-local.properties
+*.backup
\ No newline at end of file
diff --git a/mi-sql-public-demo/README.md b/mi-sql-public-demo/README.md
index 33aaf39..bbbec9a 100644
--- a/mi-sql-public-demo/README.md
+++ b/mi-sql-public-demo/README.md
@@ -1,5 +1,205 @@
-# sqldbmi
+# Azure SQL Database with Managed Identity Demo
+
+This project demonstrates how to connect to Azure SQL Database using **Azure Managed Identity** authentication with Java and the SQL Server JDBC driver. The implementation showcases a secure, credential-free way to connect to Azure SQL Database from Java applications.
+
+## Overview
+
+Azure Managed Identity provides an automatically managed identity in Microsoft Entra ID for applications to use when connecting to resources that support Microsoft Entra authentication. This eliminates the need to manage credentials in your application code.
+
+## Prerequisites
+
+Before running this application, ensure you have:
+
+1. **Azure Subscription** with appropriate permissions
+2. **Azure SQL Database** server and database created
+3. **User-Assigned Managed Identity** created and configured
+4. **Java 17+** installed
+5. **Maven 3.6+** installed
+
+## Azure Setup
+
+### 1. Create Azure SQL Database
+
+```bash
+# Create resource group
+az group create --name myResourceGroup --location eastus
+
+# Create Azure SQL Server
+az sql server create \
+ --name myserver \
+ --resource-group myResourceGroup \
+ --location eastus \
+ --admin-user sqladmin \
+ --admin-password YourPassword123!
+
+# Create database
+az sql db create \
+ --resource-group myResourceGroup \
+ --server myserver \
+ --name demo \
+ --service-objective Basic
+```
+
+### 2. Create User-Assigned Managed Identity
+
+```bash
+# Create managed identity
+az identity create \
+ --resource-group myResourceGroup \
+ --name myManagedIdentity
+
+# Get the client ID (you'll need this for configuration)
+az identity show \
+ --resource-group myResourceGroup \
+ --name myManagedIdentity \
+ --query clientId \
+ --output tsv
+```
+
+### 3. Configure SQL Database for Managed Identity
+
+```bash
+# Set Microsoft Entra admin for SQL server
+az sql server ad-admin create \
+ --resource-group myResourceGroup \
+ --server-name myserver \
+ --display-name myManagedIdentity \
+ --object-id $(az identity show --resource-group myResourceGroup --name myManagedIdentity --query principalId --output tsv)
+```
+
+### 4. Create Database User for Managed Identity
+
+Connect to your Azure SQL Database using SQL Server Management Studio, Azure Data Studio, or sqlcmd, and run:
+
+```sql
+-- Create user for managed identity
+CREATE USER [myManagedIdentity] FROM EXTERNAL PROVIDER;
+
+-- Grant necessary permissions
+ALTER ROLE db_datareader ADD MEMBER [myManagedIdentity];
+ALTER ROLE db_datawriter ADD MEMBER [myManagedIdentity];
+ALTER ROLE db_ddladmin ADD MEMBER [myManagedIdentity];
+```
+
+## Configuration
+
+### 1. Update application.properties
+
+Edit `src/main/resources/application.properties` and replace the placeholders:
+
+```properties
+# Replace with your actual Azure SQL Server name
+AZURE_SQLDB_CONNECTIONSTRING=jdbc:sqlserver://myserver.database.windows.net:1433;database=demo;encrypt=true;trustServerCertificate=false;hostNameInCertificate=*.database.windows.net;loginTimeout=30;
+
+# Replace with your managed identity client ID
+AZURE_CLIENT_ID=12345678-1234-1234-1234-123456789012
+```
+
+### 2. Environment Variables (Alternative)
+
+Instead of modifying the properties file, you can set environment variables:
+
+```bash
+export AZ_DATABASE_SERVER_NAME=myserver
+export AZURE_CLIENT_ID=12345678-1234-1234-1234-123456789012
+```
+
+## Building and Running
+
+### Local Development
+
+```bash
+# Clone the repository
+git clone
+cd mi-sql-public-demo
+
+# Compile the application
+mvn clean compile
+
+# Package the application
+mvn package
+
+# Run the application (requires Azure environment with managed identity)
+java -jar target/demo-1.0-SNAPSHOT.jar
+```
+
+### Running on Azure
+
+This application is designed to run in Azure environments that support Managed Identity:
+
+- **Azure Virtual Machines** with assigned managed identity
+- **Azure Container Instances** with managed identity
+- **Azure App Service** with managed identity enabled
+- **Azure Container Apps** with managed identity
+- **Azure Kubernetes Service (AKS)** with pod identity
+
+## Features
+
+- **Secure Authentication**: Uses Azure Managed Identity for credential-free database access
+- **Connection Validation**: Validates database connectivity with test queries
+- **Error Handling**: Comprehensive error handling and logging
+- **Property Validation**: Validates required configuration properties
+- **Logging**: Detailed logging for troubleshooting and monitoring
+
+## Troubleshooting
+
+### Common Issues
+
+1. **Authentication Failed**
+ - Verify the managed identity has been assigned to your Azure resource
+ - Ensure the managed identity has proper permissions on the SQL database
+ - Check that the client ID is correct in configuration
+
+2. **Connection Timeout**
+ - Verify network connectivity to Azure SQL Database
+ - Check firewall rules on the SQL server
+ - Ensure the connection string is correct
+
+3. **Property Validation Errors**
+ - Replace placeholder values in `application.properties`
+ - Verify environment variables are set correctly
+ - Check for typos in server names and client IDs
+
+### Logging
+
+The application provides detailed logging to help with troubleshooting:
+
+- **INFO**: Normal operation and success messages
+- **WARNING**: Non-fatal issues and fallback operations
+- **SEVERE**: Critical errors and failures
+
+### Testing Connection
+
+The application performs these validation steps:
+
+1. Loads and validates configuration properties
+2. Constructs the connection string with managed identity parameters
+3. Establishes connection to Azure SQL Database
+4. Executes test query to verify connectivity
+5. Reports connection status and server information
+
+## Security Considerations
+
+- **No Credentials**: The application doesn't store or handle database passwords
+- **Encrypted Connection**: All database connections use SSL/TLS encryption
+- **Identity Validation**: Managed identity provides secure, token-based authentication
+- **Minimal Permissions**: Grant only the minimum required database permissions
+
+## Dependencies
+
+- **Spring Cloud Azure**: Provides Azure integration and managed identity support
+- **SQL Server JDBC Driver**: Microsoft's official JDBC driver for SQL Server
+- **Java Logging API**: Standard Java logging framework
## Documentation
-For detailed information about Java application migration with GitHub Copilot, please refer to the [Quickstart: Use GitHub Copilot for app modernization and migration of Java applications](https://learn.microsoft.com/azure/developer/java/migration/migrate-github-copilot-app-modernization-for-java-quickstart-assess-migrate).
\ No newline at end of file
+For more information about Java application migration with GitHub Copilot, see:
+- [Quickstart: Use GitHub Copilot for app modernization and migration of Java applications](https://learn.microsoft.com/azure/developer/java/migration/migrate-github-copilot-app-modernization-for-java-quickstart-assess-migrate)
+
+For Azure Managed Identity documentation:
+- [What are managed identities for Azure resources?](https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview)
+- [Use managed identities to connect Azure SQL Database](https://docs.microsoft.com/en-us/azure/app-service/app-service-web-tutorial-connect-msi)
+
+## License
+
+This project is licensed under the MIT License - see the LICENSE file for details.
\ No newline at end of file
diff --git a/mi-sql-public-demo/pom.xml b/mi-sql-public-demo/pom.xml
index e6a1afb..31177a2 100644
--- a/mi-sql-public-demo/pom.xml
+++ b/mi-sql-public-demo/pom.xml
@@ -11,8 +11,9 @@
17
17
-
17
+ UTF-8
+ UTF-8
diff --git a/mi-sql-public-demo/src/main/java/com/example/MainSQL.java b/mi-sql-public-demo/src/main/java/com/example/MainSQL.java
index 5a8f9a5..cc4d20f 100644
--- a/mi-sql-public-demo/src/main/java/com/example/MainSQL.java
+++ b/mi-sql-public-demo/src/main/java/com/example/MainSQL.java
@@ -1,46 +1,153 @@
package com.example;
-import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
import java.util.Properties;
-
-import java.sql.*;
+import java.util.logging.Logger;
+import java.util.logging.Level;
import com.microsoft.sqlserver.jdbc.SQLServerDataSource;
+/**
+ * Azure SQL Database Managed Identity Connection Demo
+ *
+ * This application demonstrates how to connect to Azure SQL Database
+ * using Managed Identity authentication with the SQL Server JDBC driver.
+ */
public class MainSQL {
+ private static final Logger LOGGER = Logger.getLogger(MainSQL.class.getName());
+ private static final String PROPERTIES_FILE = "application.properties";
+
+ // Required property keys
+ private static final String AZURE_SQLDB_CONNECTIONSTRING = "AZURE_SQLDB_CONNECTIONSTRING";
+ private static final String AZURE_CLIENT_ID = "AZURE_CLIENT_ID";
public static void main(String[] args) {
+ LOGGER.info("Starting Azure SQL Database Managed Identity connection test...");
+ try {
+ Properties properties = loadProperties();
+ String connectionString = buildConnectionString(properties);
+ testConnection(connectionString);
+
+ LOGGER.info("Application completed successfully.");
+ } catch (Exception e) {
+ LOGGER.log(Level.SEVERE, "Application failed with error: " + e.getMessage(), e);
+ System.exit(1);
+ }
+ }
+
+ /**
+ * Load application properties from the classpath
+ */
+ private static Properties loadProperties() throws IOException {
Properties properties = new Properties();
- try (InputStream input = MainSQL.class.getClassLoader().getResourceAsStream("application.properties")) {
+
+ try (InputStream input = MainSQL.class.getClassLoader().getResourceAsStream(PROPERTIES_FILE)) {
if (input == null) {
- System.out.println("Sorry, unable to find application.properties");
- return;
+ throw new IOException("Unable to find " + PROPERTIES_FILE + " in classpath");
}
- // Load the properties file
+
properties.load(input);
- } catch (IOException ex) {
- ex.printStackTrace();
- return;
+ LOGGER.info("Successfully loaded properties from " + PROPERTIES_FILE);
+
+ // Validate required properties
+ validateRequiredProperties(properties);
+
+ return properties;
}
+ }
- String connString = properties.getProperty("AZURE_SQLDB_CONNECTIONSTRING");
- String clientId = properties.getProperty("AZURE_CLIENT_ID");
+ /**
+ * Validate that all required properties are present and not empty
+ */
+ private static void validateRequiredProperties(Properties properties) throws IllegalArgumentException {
+ String connectionString = properties.getProperty(AZURE_SQLDB_CONNECTIONSTRING);
+ String clientId = properties.getProperty(AZURE_CLIENT_ID);
- connString = connString + ";msiClientId=" + clientId + ";authentication=ActiveDirectoryMSI";
- System.out.print(connString);
+ if (connectionString == null || connectionString.trim().isEmpty()) {
+ throw new IllegalArgumentException(AZURE_SQLDB_CONNECTIONSTRING + " is required and cannot be empty");
+ }
- SQLServerDataSource ds = new SQLServerDataSource();
- ds.setURL(connString);
- try (Connection connection = ds.getConnection()) {
- System.out.println("Connected successfully.");
+ if (clientId == null || clientId.trim().isEmpty()) {
+ throw new IllegalArgumentException(AZURE_CLIENT_ID + " is required and cannot be empty");
+ }
+
+ // Check for placeholder values
+ if (clientId.contains("")) {
+ throw new IllegalArgumentException(AZURE_CLIENT_ID + " contains placeholder value. Please update with your actual Managed Identity client ID");
+ }
+
+ if (connectionString.contains("${AZ_DATABASE_SERVER_NAME}")) {
+ throw new IllegalArgumentException(AZURE_SQLDB_CONNECTIONSTRING + " contains placeholder value. Please update with your actual server name");
+ }
+
+ LOGGER.info("All required properties validated successfully");
+ }
+
+ /**
+ * Build the complete connection string with Managed Identity authentication
+ */
+ private static String buildConnectionString(Properties properties) {
+ String baseConnectionString = properties.getProperty(AZURE_SQLDB_CONNECTIONSTRING);
+ String clientId = properties.getProperty(AZURE_CLIENT_ID);
+
+ String connectionString = baseConnectionString + ";msiClientId=" + clientId + ";authentication=ActiveDirectoryMSI";
+
+ LOGGER.info("Built connection string for Managed Identity authentication");
+ // Log connection string without sensitive information
+ String logSafeConnectionString = connectionString.replaceAll("msiClientId=[^;]+", "msiClientId=***");
+ LOGGER.info("Connection string: " + logSafeConnectionString);
+
+ return connectionString;
+ }
+
+ /**
+ * Test the database connection and perform a simple query
+ */
+ private static void testConnection(String connectionString) throws SQLException {
+ LOGGER.info("Attempting to connect to Azure SQL Database...");
+
+ SQLServerDataSource dataSource = new SQLServerDataSource();
+ dataSource.setURL(connectionString);
+
+ try (Connection connection = dataSource.getConnection()) {
+ LOGGER.info("Successfully connected to Azure SQL Database using Managed Identity!");
+
+ // Test the connection with a simple query
+ performConnectionTest(connection);
+
} catch (SQLException e) {
- e.printStackTrace();
+ LOGGER.log(Level.SEVERE, "Failed to connect to Azure SQL Database: " + e.getMessage(), e);
+ throw e;
}
}
-
+ /**
+ * Perform a simple test query to validate the connection
+ */
+ private static void performConnectionTest(Connection connection) throws SQLException {
+ LOGGER.info("Performing connection validation test...");
+
+ try (Statement statement = connection.createStatement();
+ ResultSet resultSet = statement.executeQuery("SELECT 1 as test_value, GETDATE() as current_time")) {
+
+ if (resultSet.next()) {
+ int testValue = resultSet.getInt("test_value");
+ String currentTime = resultSet.getString("current_time");
+
+ LOGGER.info("Connection test successful - Test value: " + testValue + ", Server time: " + currentTime);
+ } else {
+ LOGGER.warning("Connection test query returned no results");
+ }
+ } catch (SQLException e) {
+ LOGGER.log(Level.WARNING, "Connection test query failed: " + e.getMessage(), e);
+ throw e;
+ }
+ }
}
\ No newline at end of file
diff --git a/mi-sql-public-demo/src/main/resources/application.properties b/mi-sql-public-demo/src/main/resources/application.properties
index ed7d015..97e376e 100644
--- a/mi-sql-public-demo/src/main/resources/application.properties
+++ b/mi-sql-public-demo/src/main/resources/application.properties
@@ -1,9 +1,42 @@
+# Azure SQL Database Managed Identity Configuration
+# ================================================
+
+# Azure SQL Database Connection String
+# Replace ${AZ_DATABASE_SERVER_NAME} with your actual Azure SQL Server name
+# Example: jdbc:sqlserver://myserver.database.windows.net:1433;database=demo;encrypt=true;trustServerCertificate=false;hostNameInCertificate=*.database.windows.net;loginTimeout=30;
AZURE_SQLDB_CONNECTIONSTRING=jdbc:sqlserver://${AZ_DATABASE_SERVER_NAME}.database.windows.net:1433;database=demo;encrypt=true;trustServerCertificate=false;hostNameInCertificate=*.database.windows.net;loginTimeout=30;
+
+# Azure Managed Identity Client ID
+# Replace with your actual Managed Identity Client ID
+# You can find this in the Azure Portal under your User Assigned Managed Identity resource
+# Example: AZURE_CLIENT_ID=12345678-1234-1234-1234-123456789012
AZURE_CLIENT_ID=
-# Enable Azure managed identity for Spring Cloud Azure
+# Spring Cloud Azure Configuration
+# ===============================
+# Enable Azure managed identity authentication for Spring Cloud Azure
spring.cloud.azure.credential.managed-identity-enabled=true
+
+# Set the client ID for the managed identity
spring.cloud.azure.credential.client-id=${AZURE_CLIENT_ID}
+# Spring DataSource Configuration (for Spring Boot applications)
+# ==============================================================
# Add datasource URL for Azure SQL using Managed Identity authentication
-spring.datasource.url=jdbc:sqlserver://${AZ_DATABASE_SERVER_NAME}.database.windows.net:1433;database=demo;encrypt=true;trustServerCertificate=false;hostNameInCertificate=*.database.windows.net;loginTimeout=30;authentication=ActiveDirectoryMSI
\ No newline at end of file
+# This configuration is used when the application is integrated with Spring Boot
+spring.datasource.url=jdbc:sqlserver://${AZ_DATABASE_SERVER_NAME}.database.windows.net:1433;database=demo;encrypt=true;trustServerCertificate=false;hostNameInCertificate=*.database.windows.net;loginTimeout=30;authentication=ActiveDirectoryMSI
+
+# Additional Configuration Options
+# ===============================
+# Uncomment and configure the following properties as needed:
+
+# Database connection pool settings
+# spring.datasource.hikari.maximum-pool-size=10
+# spring.datasource.hikari.minimum-idle=2
+# spring.datasource.hikari.connection-timeout=30000
+# spring.datasource.hikari.idle-timeout=600000
+# spring.datasource.hikari.max-lifetime=1800000
+
+# Logging configuration
+# logging.level.com.example=INFO
+# logging.level.com.microsoft.sqlserver.jdbc=WARN
\ No newline at end of file
From 1a3e12244f510a9644c162024f0c0ba1b9e70b3a Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 10 Sep 2025 20:55:18 +0000
Subject: [PATCH 4/4] Add health check utility and final documentation
improvements
Co-authored-by: richposada <454664+richposada@users.noreply.github.com>
---
mi-sql-public-demo/README.md | 31 ++++
mi-sql-public-demo/dependency-reduced-pom.xml | 2 +
.../java/com/example/util/HealthCheck.java | 150 ++++++++++++++++++
3 files changed, 183 insertions(+)
create mode 100644 mi-sql-public-demo/src/main/java/com/example/util/HealthCheck.java
diff --git a/mi-sql-public-demo/README.md b/mi-sql-public-demo/README.md
index bbbec9a..432a477 100644
--- a/mi-sql-public-demo/README.md
+++ b/mi-sql-public-demo/README.md
@@ -140,6 +140,37 @@ This application is designed to run in Azure environments that support Managed I
- **Error Handling**: Comprehensive error handling and logging
- **Property Validation**: Validates required configuration properties
- **Logging**: Detailed logging for troubleshooting and monitoring
+- **Health Check Utility**: Built-in health check for monitoring and deployment validation
+
+## Running the Application
+
+### Main Application
+
+```bash
+# Run the main application
+java -jar target/demo-1.0-SNAPSHOT.jar
+
+# Or run the main class directly
+java -cp target/classes com.example.MainSQL
+```
+
+### Health Check Utility
+
+The application includes a health check utility that can be used for monitoring and deployment validation:
+
+```bash
+# Run health check
+java -cp target/classes com.example.util.HealthCheck
+
+# Health check will exit with code 0 for success, 1 for failure
+# Perfect for monitoring scripts and deployment pipelines
+```
+
+The health check provides:
+- Connection validation with response time measurement
+- Detailed error reporting and logging
+- Exit codes for automation and monitoring systems
+- Lightweight operation suitable for frequent monitoring
## Troubleshooting
diff --git a/mi-sql-public-demo/dependency-reduced-pom.xml b/mi-sql-public-demo/dependency-reduced-pom.xml
index 9a8898f..9640899 100644
--- a/mi-sql-public-demo/dependency-reduced-pom.xml
+++ b/mi-sql-public-demo/dependency-reduced-pom.xml
@@ -52,5 +52,7 @@
17
17
17
+ UTF-8
+ UTF-8
diff --git a/mi-sql-public-demo/src/main/java/com/example/util/HealthCheck.java b/mi-sql-public-demo/src/main/java/com/example/util/HealthCheck.java
new file mode 100644
index 0000000..6e83c08
--- /dev/null
+++ b/mi-sql-public-demo/src/main/java/com/example/util/HealthCheck.java
@@ -0,0 +1,150 @@
+package com.example.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Properties;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.microsoft.sqlserver.jdbc.SQLServerDataSource;
+
+/**
+ * Health Check utility for Azure SQL Database Managed Identity connection
+ *
+ * This utility provides health check functionality that can be used for:
+ * - Deployment validation
+ * - Monitoring and alerting
+ * - Troubleshooting connectivity issues
+ */
+public class HealthCheck {
+
+ private static final Logger LOGGER = Logger.getLogger(HealthCheck.class.getName());
+
+ public static class HealthResult {
+ private final boolean healthy;
+ private final String message;
+ private final long responseTimeMs;
+
+ public HealthResult(boolean healthy, String message, long responseTimeMs) {
+ this.healthy = healthy;
+ this.message = message;
+ this.responseTimeMs = responseTimeMs;
+ }
+
+ public boolean isHealthy() { return healthy; }
+ public String getMessage() { return message; }
+ public long getResponseTimeMs() { return responseTimeMs; }
+
+ @Override
+ public String toString() {
+ return String.format("HealthResult{healthy=%s, responseTime=%dms, message='%s'}",
+ healthy, responseTimeMs, message);
+ }
+ }
+
+ /**
+ * Perform a health check on the Azure SQL Database connection
+ *
+ * @return HealthResult containing the health status and details
+ */
+ public static HealthResult checkDatabaseHealth() {
+ long startTime = System.currentTimeMillis();
+
+ try {
+ Properties properties = loadProperties();
+ String connectionString = buildConnectionString(properties);
+
+ SQLServerDataSource dataSource = createDataSource(connectionString);
+ try (Connection connection = dataSource.getConnection()) {
+
+ // Perform a simple health check query
+ boolean querySuccess = executeHealthCheckQuery(connection);
+ long responseTime = System.currentTimeMillis() - startTime;
+
+ if (querySuccess) {
+ return new HealthResult(true, "Database connection healthy", responseTime);
+ } else {
+ return new HealthResult(false, "Health check query failed", responseTime);
+ }
+
+ }
+ } catch (IOException e) {
+ long responseTime = System.currentTimeMillis() - startTime;
+ LOGGER.log(Level.WARNING, "Configuration error during health check", e);
+ return new HealthResult(false, "Configuration error: " + e.getMessage(), responseTime);
+
+ } catch (SQLException e) {
+ long responseTime = System.currentTimeMillis() - startTime;
+ LOGGER.log(Level.WARNING, "Database connection error during health check", e);
+ return new HealthResult(false, "Database connection error: " + e.getMessage(), responseTime);
+
+ } catch (Exception e) {
+ long responseTime = System.currentTimeMillis() - startTime;
+ LOGGER.log(Level.SEVERE, "Unexpected error during health check", e);
+ return new HealthResult(false, "Unexpected error: " + e.getMessage(), responseTime);
+ }
+ }
+
+ private static Properties loadProperties() throws IOException {
+ Properties properties = new Properties();
+ try (InputStream input = HealthCheck.class.getClassLoader().getResourceAsStream("application.properties")) {
+ if (input == null) {
+ throw new IOException("Unable to find application.properties in classpath");
+ }
+ properties.load(input);
+ return properties;
+ }
+ }
+
+ private static String buildConnectionString(Properties properties) {
+ String baseConnectionString = properties.getProperty("AZURE_SQLDB_CONNECTIONSTRING");
+ String clientId = properties.getProperty("AZURE_CLIENT_ID");
+
+ if (baseConnectionString == null || clientId == null) {
+ throw new IllegalArgumentException("Required connection properties not found");
+ }
+
+ return baseConnectionString + ";msiClientId=" + clientId + ";authentication=ActiveDirectoryMSI";
+ }
+
+ private static SQLServerDataSource createDataSource(String connectionString) {
+ SQLServerDataSource dataSource = new SQLServerDataSource();
+ dataSource.setURL(connectionString);
+ return dataSource;
+ }
+
+ private static boolean executeHealthCheckQuery(Connection connection) {
+ try (Statement statement = connection.createStatement();
+ ResultSet resultSet = statement.executeQuery("SELECT 1 as health_check")) {
+
+ return resultSet.next() && resultSet.getInt("health_check") == 1;
+
+ } catch (SQLException e) {
+ LOGGER.log(Level.WARNING, "Health check query execution failed", e);
+ return false;
+ }
+ }
+
+ /**
+ * Command-line interface for health check
+ */
+ public static void main(String[] args) {
+ LOGGER.info("Starting Azure SQL Database health check...");
+
+ HealthResult result = checkDatabaseHealth();
+
+ if (result.isHealthy()) {
+ LOGGER.info("Health check PASSED: " + result.getMessage() +
+ " (Response time: " + result.getResponseTimeMs() + "ms)");
+ System.exit(0);
+ } else {
+ LOGGER.severe("Health check FAILED: " + result.getMessage() +
+ " (Response time: " + result.getResponseTimeMs() + "ms)");
+ System.exit(1);
+ }
+ }
+}
\ No newline at end of file