diff --git a/asset-manager/README.md b/asset-manager/README.md
index 059de92..778dc08 100644
--- a/asset-manager/README.md
+++ b/asset-manager/README.md
@@ -1,42 +1,53 @@
-# Workshop: migrate this project to Azure
-
-- [Workshop: migrate this project to Azure](#workshop-migrate-this-project-to-azure)
- - [About this Project](#about-this-project)
- - [Original Infrastructure](#original-infrastructure)
- - [Original Architecture](#original-architecture)
- - [Migrated Infrastructure](#migrated-infrastructure)
- - [Migrated Architecture](#migrated-architecture)
- - [Prerequisites](#prerequisites)
- - [Install GitHub Copilot app modernization](#install-github-copilot-app-modernization)
- - [Migrate the Sample Java Application](#migrate-the-sample-java-application)
- - [Assess Your Java Application](#assess-your-java-application)
- - [Migrate to Azure Database for PostgreSQL Flexible Server using Predefined Tasks](#migrate-to-azure-database-for-postgresql-flexible-server-using-predefined-tasks)
- - [Migrate to Azure Blob Storage and Azure Service Bus using Custom Tasks](#migrate-to-azure-blob-storage-and-azure-service-bus-using-custom-tasks)
- - [Deploy to Azure](#deploy-to-azure)
- - [Clean up](#clean-up)
-
-GitHub Copilot app modernization, assists with app assessment, planning and code remediation. It automates repetitive tasks, boosting developer confidence and speeding up the Azure migration and ongoing optimization.
+# Asset Manager
-In this workshop, you learn how to use GitHub Copilot app modernization to assess and migrate a sample Java application `asset-manager` to Azure.
+This document serves as a comprehensive workshop guide that will walk you through the process of migrating a Java application to Azure using GitHub Copilot app modernization. The workshop covers assessment, Java/framework upgrades, migration to Azure services, containerization, and deployment.
-## About this Project
+**What the modernization Process Will Do:**
+The modernization will transform your application from the outdated technologies to a modern Azure-native solution. This includes upgrading from Java 8 to Java 21, migrating from Spring Boot 2.x to 3.x, replacing AWS S3 with Azure Blob Storage, switching from RabbitMQ to Azure Service Bus, migrating to Azure Database for PostgreSQL, implementing managed identity authentication, adding health checks, containerizing the applications, and preparing them for cloud deployment with proper monitoring.
-This application consists of two sub-modules, **Web** and **Worker**. Both of them contain functions of using storage service and message queue. To demonstrate the migration process, this GitHub repository is mainly composed of 3 different branches:
+## Table of Contents
-- [`source`](https://github.com/Azure-Samples/java-migration-copilot-samples/tree/source/asset-manager) branch: The original project before being migrated to Azure service.
-- [`main`](https://github.com/Azure-Samples/java-migration-copilot-samples/tree/main/asset-manager) branch: Only the `web` module is migrated to use Azure service. This branch will be used for the workshop.
-- [`expected`](https://github.com/Azure-Samples/java-migration-copilot-samples/tree/expected/asset-manager) branch: The is the final migrated state, and both `web` and `worker` modules are migrated to Azure.
-
-### Original Infrastructure
+- [Overview](#overview)
+- [Current Architecture](#current-architecture)
+- [Run Locally](#run-locally)
+- [App Modernization](#app-modernization)
+ - [Install GitHub Copilot app modernization](#install-github-copilot-app-modernization)
+ - [Assess Your Java Application](#assess-your-java-application)
+ - [Upgrade Runtime & Frameworks](#upgrade-runtime--frameworks)
+ - [Migrate to Azure Database for PostgreSQL Flexible Server using Predefined Tasks](#migrate-to-azure-database-for-postgresql-flexible-server-using-predefined-tasks)
+ - [Migrate to Azure Blob Storage using Predefined Tasks](#migrate-to-azure-blob-storage-using-predefined-tasks)
+ - [Migrate to Azure Service Bus using Predefined Tasks](#migrate-to-azure-service-bus-using-predefined-tasks)
+ - [Expose health endpoints using Custom Tasks](#expose-health-endpoints-using-custom-tasks)
+ - [Containerize Applications](#containerize-applications)
+ - [Deploy to Azure](#deploy-to-azure)
-The project uses the following infrastructure, in [`source`](https://github.com/Azure-Samples/java-migration-copilot-samples/tree/source/asset-manager) branch:
+## Overview
+The [main](https://github.com/Azure-Samples/java-migration-copilot-samples/tree/main/asset-manager) branch of the asset-manager project is the original state before being migrated to Azure services. It is organized as follows:
* AWS S3 for image storage, using password-based authentication (access key/secret key)
* RabbitMQ for message queuing, using password-based authentication
* PostgreSQL database for metadata storage, using password-based authentication
-### Original Architecture
-
+In this workshop, you will use the **GitHub Copilot app modernization** extension to assess, upgrade, migrate, and finally deploy the project to Azure.
+
+**Time Estimates:**
+The complete workshop takes approximately **2 hours** to complete. Here's the breakdown for each major step:
+- **Assess Your Java Application**: ~5 minutes
+- **Upgrade Runtime & Frameworks**: ~10 minutes
+- **Migrate to Azure Database for PostgreSQL**: ~15 minutes
+- **Migrate to Azure Blob Storage**: ~15 minutes
+- **Migrate to Azure Service Bus**: ~15 minutes
+- **Expose Health Endpoints**: ~15 minutes
+- **Containerize Applications**: ~5 minutes
+- **Deploy to Azure**: ~40 minutes
+
+There are 3 branches we have prepared for you in case you have any problems with any steps in this workshop:
+* [main](https://github.com/Azure-Samples/java-migration-copilot-samples/tree/main/asset-manager): The original state of the asset-manager application.
+* [workshop/java-upgrade](https://github.com/Azure-Samples/java-migration-copilot-samples/tree/workshop/java-upgrade/asset-manager): The project state after assessment and Java upgrading steps.
+* [workshop/expected](https://github.com/Azure-Samples/java-migration-copilot-samples/tree/workshop/expected/asset-manager): The project state after assessment, Java upgrading, and migration steps.
+* [workshop/deployment-expected](https://github.com/Azure-Samples/java-migration-copilot-samples/tree/workshop/deployment-expected/asset-manager): The project state after containerization and deployment steps.
+
+## Current Architecture
```mermaid
flowchart TD
@@ -105,225 +116,176 @@ class User user
```
Password-based authentication
-### Migrated Infrastructure
-
-After migration, the project will use the following Azure services, in [`expected`](https://github.com/Azure-Samples/java-migration-copilot-samples/tree/expected/asset-manager) branch:
-
-* Azure Blob Storage for image storage, using managed identity authentication
-* Azure Service Bus for message queuing, using managed identity authentication
-* Azure Database for PostgreSQL for metadata storage, using managed identity authentication
+## Run Locally
-### Migrated Architecture
+Clone the repository and open the asset-manager folder to run the current project locally:
-```mermaid
-flowchart TD
-
-%% Applications
-WebApp[Web Application]
-Worker[Worker Service]
-
-%% Azure Storage Components
-AzBlob[(Azure Blob Storage)]
-LocalFS[("Local File System dev only")]
-
-%% Azure Message Broker
-ServiceBus(Azure Service Bus)
-
-%% Azure Database
-AzPostgreSQL[(Azure PostgreSQL)]
-
-%% Queues
-Queue[image-processing queue]
-RetryQueue[retry queue]
-
-%% User
-User([User])
+```bash
+git clone https://github.com/Azure-Samples/java-migration-copilot-samples.git
+cd java-migration-copilot-samples/asset-manager
+```
-%% User Flow
-User -->|Upload Image| WebApp
-User -->|View Images| WebApp
+**Prerequisites**:
+- [JDK 8](https://learn.microsoft.com/en-us/java/openjdk/download#openjdk-8): Required for running the initial application locally.
+- [Maven 3.6.0+](https://maven.apache.org/install.html): Required to build the application locally.
+- [Docker](https://docs.docker.com/desktop/): Required for running the application locally.
-%% Web App Flows
-WebApp -->|Store Original Image| AzBlob
-WebApp -->|Store Original Image| LocalFS
-WebApp -->|Send Processing Message| ServiceBus
-WebApp -->|Store Metadata| AzPostgreSQL
-WebApp -->|Retrieve Images| AzBlob
-WebApp -->|Retrieve Images| LocalFS
-WebApp -->|Retrieve Metadata| AzPostgreSQL
+Run the following commands to start the apps locally. This will:
+* Use the local file system instead of S3 to store images
+* Launch RabbitMQ and PostgreSQL using Docker
-%% Service Bus Flow
-ServiceBus -->|Push Message| Queue
-Queue -->|Processing Failed| RetryQueue
-RetryQueue -->|After 1 min delay| Queue
-Queue -->|Consume Message| Worker
+Windows:
-%% Worker Flow
-Worker -->|Download Original| AzBlob
-Worker -->|Download Original| LocalFS
-Worker -->|Upload Thumbnail| AzBlob
-Worker -->|Upload Thumbnail| LocalFS
-Worker -->|Store Metadata| AzPostgreSQL
-Worker -->|Retrieve Metadata| AzPostgreSQL
+```batch
+scripts\startapp.cmd
+```
-%% Styling
-classDef app fill:#90caf9,stroke:#0d47a1,color:#0d47a1
-classDef storage fill:#68B3A1,stroke:#006064,color:#006064
-classDef broker fill:#B39DDB,stroke:#4527A0,color:#4527A0
-classDef db fill:#90CAF9,stroke:#1565C0,color:#1565C0
-classDef queue fill:#81C784,stroke:#2E7D32,color:#2E7D32
-classDef user fill:#ef9a9a,stroke:#b71c1c,color:#b71c1c
+Linux:
-class WebApp,Worker app
-class AzBlob,LocalFS storage
-class ServiceBus broker
-class AzPostgreSQL db
-class Queue,RetryQueue queue
-class User user
+```bash
+scripts/startapp.sh
```
-Managed identity based authentication
-## Prerequisites
+To stop, run `stopapp.cmd` or `stopapp.sh` in the `scripts` directory.
-To successfully complete this workshop, you need the following:
+## App Modernization
-- [VSCode](https://code.visualstudio.com/): The latest version is recommended.
-- [A Github account with Github Copilot enabled](https://github.com/features/copilot): All plans are supported, including the Free plan.
-- [GitHub Copilot extension in VSCode](https://code.visualstudio.com/docs/copilot/overview): The latest version is recommended.
-- [JDK 21](https://learn.microsoft.com/en-us/java/openjdk/download#openjdk-21): Required for the code remediation feature and running the initial application locally.
-- [Maven 3.9.9](https://maven.apache.org/install.html): Required for the assessment and code remediation feature.
+The following sections guide you through the process of modernizing the sample Java application `asset-manager` to Azure using GitHub Copilot app modernization.
-If you want to deploy the application to Azure, the following are required:
-- [Azure subscription](https://azure.microsoft.com/free/): Required to deploy the migrated application to Azure.
-- [Azure CLI](https://docs.microsoft.com/cli/azure/install-azure-cli): Required if you deploy the migrated application to Azure locally. The latest version is recommended.
-- Fork the [GitHub repository](https://github.com/Azure-Samples/java-migration-copilot-samples) that contains the sample Java application. Please ensure to **uncheck** the default selection "Copy the `main` branch only". Clone it to your local machine. Open the `asset-manager` folder in VSCode and checkout the `main` branch.
+**Prerequisites**:
+- A GitHub account with [GitHub Copilot](https://github.com/features/copilot) enabled. A Pro, Pro+, Business, or Enterprise plan is required.
+- One of the following IDEs:
+ - The latest version of [Visual Studio Code](https://code.visualstudio.com/). Must be version 1.101 or later.
+ - [GitHub Copilot in Visual Studio Code](https://code.visualstudio.com/docs/copilot/overview). For setup instructions, see [Set up GitHub Copilot in Visual Studio Code](https://code.visualstudio.com/docs/copilot/setup). Be sure to sign in to your GitHub account within Visual Studio Code.
+ - [GitHub Copilot app modernization](https://marketplace.visualstudio.com/items?itemName=vscjava.migrate-java-to-azure). Restart Visual Studio Code after installation.
+ - The latest version of [IntelliJ IDEA](https://www.jetbrains.com/idea/download). Must be version 2023.3 or later.
+ - [GitHub Copilot](https://plugins.jetbrains.com/plugin/17718-github-copilot). Must be version 1.5.59 or later. For more instructions, see [Set up GitHub Copilot in IntelliJ IDEA](https://docs.github.com/en/copilot/get-started/quickstart). Be sure to sign in to your GitHub account within IntelliJ IDEA.
+ - [GitHub Copilot app modernization](https://plugins.jetbrains.com/plugin/28791-github-copilot-app-modernization). Restart IntelliJ IDEA after installation. If you don't have GitHub Copilot installed, you can install GitHub Copilot app modernization directly.
+ - For more efficient use of Copilot in app modernization: in the IntelliJ IDEA settings, select the **Tools** > **GitHub Copilot** configuration window, and then select **Auto-approve** and **Trust MCP Tool Annotations**. For more information, see [Configure settings for GitHub Copilot app modernization to optimize the experience for IntelliJ](configure-settings-intellij.md).
+- [Java JDK](/java/openjdk/download) for both the source and target JDK versions.
+- [Maven](https://maven.apache.org/download.cgi) or [Gradle](https://gradle.org/install/) to build Java projects.
+- A Git-managed Java project using Maven or Gradle.
+- For Maven-based projects: access to the public Maven Central repository.
+- In the Visual Studio Code settings, make sure `chat.extensionTools.enabled` is set to `true`. This setting might be controlled by your organization.
-## Install GitHub Copilot app modernization
+> Note: If you're using Gradle, only the Gradle wrapper version 5+ is supported. The Kotlin Domain Specific Language (DSL) isn't supported.
+>
+> The function `My Tasks` isn't supported yet for IntelliJ IDEA.
-In VSCode, open the Extensions view from Activity Bar, search `GitHub Copilot app modernization` extension in marketplace. Select the Install button on the extension. After installation completes, you should see a notification in the bottom-right corner of VSCode confirming success.
+### Install GitHub Copilot app modernization
-## Migrate the Sample Java Application
+In VSCode, open the Extensions view from the Activity Bar, search for the `GitHub Copilot app modernization` extension in the marketplace. Click the Install button for the extension. After installation completes, you should see a notification in the bottom-right corner of VSCode confirming success.
-The following sections guide you through the process of migrating the sample Java application `asset-manager` to Azure using GitHub Copilot app modernization.
+**Alternative: IntelliJ IDEA**
+Alternatively, you can use IntelliJ IDEA. Open **File** > **Settings** (or **IntelliJ IDEA** > **Preferences** on macOS), navigate to **Plugins** > **Marketplace**, search for `GitHub Copilot app modernization`, and click **Install**. Restart IntelliJ IDEA if prompted.
### Assess Your Java Application
The first step is to assess the sample Java application `asset-manager`. The assessment provides insights into the application's readiness for migration to Azure.
-1. Open the VS code with all the prerequisites installed on the asset manager by changing the directory to the `asset-manager` directory and running `code .` in that directory.
-1. Open the extension `GitHub Copilot app modernization`.
-1. In the **QUICKSTART** view, click **Migrate to Azure** button to trigger the Modernization Assessor.
+1. Open VS Code with all the prerequisites installed for the asset manager by changing the directory to the `asset-manager` directory and running `code .` in that directory.
+1. Open the `GitHub Copilot app modernization` extension.
+1. In the **QUICKSTART** view, click the **Migrate to Azure** button to trigger app assessment.

1. Wait for the assessment to be completed and the report to be generated.
1. Review the **Assessment Report**. Select the **Issues** tab to view the proposed solutions for the issues identified in the report.
-1. For this workshop, select **Migrate to Azure Database for PostgreSQL (Spring)** in the Solution list, then click **Run Task**.
- 
+### Upgrade Runtime & Frameworks
-### Migrate to Azure Database for PostgreSQL Flexible Server using Predefined Tasks
+1. In the **Java Upgrade** table at the bottom of the **Issues** tab, click the **Run Task** button of the first entry **Java Version Upgrade**.
-1. After clicking the **Run Task** button in the Assessment Report, Copilot Chat panel will be opened with Agent Mode.
-1. The Copilot Agent will firstly analyze the project and generate a migration plan.
-1. After the plan is generated, Copilot chat will stop with two generated files: **plan.md** and **progress.md**. Please manually input "Continue" or "Proceed" in the chat to confirm the plan and proceed its following actions to execute the plan.
-1. When the code is migrated, the extension will prepare the **CVE Validation and Fixing** process. Click **Allow** to proceed.
-1. Review the proposed code changes and click **Keep** to apply them.
+ 
+1. After clicking the **Run Task** button, the Copilot Chat panel will open with Agent Mode. The agent will check out a new branch and start upgrading the JDK version and Spring/Spring Boot framework. Click **Allow** for any requests from the agent.
+
+### Migrate to Azure Database for PostgreSQL Flexible Server using Predefined Tasks
-### Option 1 - Migrate to Azure Blob Storage using Predefined Tasks
+Then you can migrate the sample Java application `asset-manager` to Azure.
-At this stage, you can use the predefined tasks for other migration scenarios showed in this section, or use the custom tasks showed in the next section (option 2).
+> Note: We've set up a [workshop/java-upgrade](https://github.com/Azure-Samples/java-migration-copilot-samples/tree/workshop/java-upgrade/asset-manager) branch where the Java upgrade has already been completed. Feel free to switch to this branch if you'd like to skip ahead and continue with the rest of the workshop.
-1. Click the **Run Task** in the Assessment Report, on the right of the row `Storage Migration (AWS S3)` - `Migrate from AWS S3 to Azure Blob Storage`.
-2. The followed steps are the same as the above PostgreSQL server migration.
+1. For this workshop, select **Migrate to Azure Database for PostgreSQL (Spring)** in the Solution list, then click **Run Task**.
-### Option 2 - Migrate to Azure Blob Storage and Azure Service Bus using Custom Tasks
+ 
+1. After clicking the **Run Task** button in the Assessment Report, the Copilot Chat panel will open with Agent Mode.
+1. The Copilot Agent will first analyze the project and generate a migration plan.
+1. After the plan is generated, Copilot Chat will stop with two generated files: **plan.md** and **progress.md**. If prompted, enter "Continue" or "Proceed" in the chat to confirm and execute the plan.
+1. When the code is migrated, the extension will prepare the **CVE Validation and Fixing** process. Click **Allow** to proceed.
+1. Review the proposed code changes and click **Keep** to apply them.
-The Application `asset-manager` used AWS S3 for image storage and Spring AMQP with RabbitMQ for message queuing. We have already migrated the code of **Web** module to use Azure Blob Storage and Azure Service Bus. These changes are recorded in two separate commits in the `main` branch.
+### Migrate to Azure Blob Storage using Predefined Tasks
-The following steps demonstrate how to generate custom formulas based on those existing commits. Then, you can migrate **Worker** module to use Azure Blob Storage and Azure Service Bus as well, using the created custom formulas.
+1. Click the **Run Task** in the Assessment Report, on the right of the row `Storage Migration (AWS S3)` - `Migrate from AWS S3 to Azure Blob Storage`.
+1. The following steps are the same as the above PostgreSQL server migration.
-1. Open the sidebar of `GITHUB COPILOT APP MODERNIZATION`. Hover the mouse over the **Tasks** view. Select **Create a Custom Task**.
+### Migrate to Azure Service Bus using Predefined Tasks
- 
-1. In the popped up quick-pick window, select **Create new task**.
+1. Click the **Run Task** in the Assessment Report, on the right of the row `Messaging Service Migration (Spring AMQP RabbitMQ)` - `Migrate from RabbitMQ(AMQP) to Azure Service Bus`.
+1. The following steps are the same as the above PostgreSQL server migration.
- 
-1. Type **migrate web** to search for the commits that migrated the **Web** module, and you should see two commits listed:
- * migrate web RabbitMQ to azure service bus
- * migrate web s3 to azure blob storage
+### Expose health endpoints using Custom Tasks
- 
-1. You will create two custom tasks based on the two commits. First, create the task for migrating RabbitMQ. Select the commit of **migrate web RabbitMQ to azure service bus**, click OK.
-1. For the next question of **Select uncommitted changes (Optional)**, select nothing and click OK.
-1. For the next question of **Describe changes using local files (Optional)**, choose **Skip file selection**.
+In this section, you will use custom tasks to expose health endpoints for your applications instead of writing code yourself. The following steps demonstrate how to generate custom tasks based on external web links and proper prompts.
- 
-1. Default task name will be generated. Give it a new name: "custom task migrate RabbitMQ". Press `Enter` to confirm. Then, task description, and search patterns will be generated in order. Press `Enter` repeatedly to confirm.
-1. Now, the custom task for migrating RabbitMQ is generated and shows under the item of `My Tasks` of the `Tasks` view.
-1. Create another custom task for migrating S3. Follow the same steps you just did, select the commit **migrate web s3 to azure blob storage** to create a new custom task with name: "custom task migrate s3".
-1. Now, the two custom tasks are ready.
+> Note: Custom tasks are not supported for the IntelliJ IDEA plugin. If you are using IntelliJ IDEA, you can skip this section.
- 
-1. Select and run the two custom tasks one by one you created in the `Tasks` view of `GITHUB COPILOT APP MODERNIZATION`, one at a time.
+1. Open the sidebar of `GITHUB COPILOT APP MODERNIZATION`. Click the `+` button in the **Tasks** view to create a custom task.
- 
+ 
+1. In the opened tab, enter the **Task Name** and **Task Prompt** as shown below:
+ - **Task Name**: Expose health endpoint via Spring Boot Actuator
+ - **Task Prompt**: You are a Spring Boot developer assistant, follow the Spring Boot Actuator documentation to add basic health endpoints for Azure Container Apps deployment.
+1. Click the **Add References** button to add the Spring Boot Actuator official documentation as references.
+
+ 
+1. In the popped-up quick-pick window, select **External links**. Then paste the following link: `https://docs.spring.io/spring-boot/reference/actuator/endpoints.html`. Click **Save** to create the task.
+1. Click the **Run** button to trigger the custom task.
1. Follow the same steps as the predefined task to review and apply the changes.
1. Review the proposed code changes and click **Keep** to apply them.
-## Deploy to Azure
-
-At this point, you have successfully migrated the sample Java application `asset-manager` to Migrate to Azure Database for PostgreSQL (Spring), Azure Blob Storage, and Azure Service Bus. Now, you can deploy the migrated application to Azure using the Azure CLI after you identify a working location for your Azure resources.
+### Containerize Applications
-For example, an Azure Database for PostgreSQL Flexible Server requires a location that supports the service. Follow the instructions below to find a suitable location.
+Now that you have successfully migrated your Java application to use Azure services, the next step is to prepare it for cloud deployment by containerizing both the web and worker modules. In this section, you will use **Containerization Tasks** to containerize your migrated applications.
+> Note: If you encounter any issues with the previous migration step, you can directly proceed with the containerization step using the [workshop/expected](https://github.com/Azure-Samples/java-migration-copilot-samples/tree/workshop/expected/asset-manager) branch.
-1. Run the following command to list all available locations for the current subscription.
+1. Open the sidebar of `GITHUB COPILOT APP MODERNIZATION`. In **Tasks** view, click the **Run Task** button of **Java** -> **Containerization Tasks** -> **Containerize Application**.
+
+ 
- ```bash
- az account list-locations -o table
- ```
+1. A predefined prompt will be populated in the Copilot Chat panel with Agent Mode. Copilot Agent will start to analyze the workspace and to create a **containerization-plan.copiotmd** with the containerization plan.
-1. Select a location from column **Name** in the output.
+ 
+1. View the plan and collaborate with Copilot Agent as it follows the **Execution Steps** in the plan by clicking **Continue**/**Allow** in pop-up chat notifications to run commands. Some of the execution steps leverage agentic tools of **Container Assist**.
-1. Run the following command to list all available SKUs in the selected location for Azure Database for PostgreSQL Flexible Server:
+
+1. Copilot Agent will help generate Dockerfile, build Docker images and fix build errors if there are any. Click **Keep** to apply the generated code.
- ```bash
- az postgres flexible-server list-skus --location -o table
- ```
+### Deploy to Azure
-1. If you see the output contains the SKU `Standard_B1ms` and the **Tier** is `Burstable`, you can use the location for the deployment. Otherwise, try another location.
+At this point, you have successfully migrated the sample Java application `asset-manager` to Azure Database for PostgreSQL (Spring), Azure Blob Storage, and Azure Service Bus, and exposed health endpoints via Spring Boot Actuator. Now, you can start the deployment to Azure.
+> Note: If you encounter any issues with the previous migration step, you can directly proceed with the deployment step using the [workshop/expected](https://github.com/Azure-Samples/java-migration-copilot-samples/tree/workshop/expected/asset-manager) branch.
- ```text
- SKU Tier VCore Memory Max Disk IOPS
- ----------------- --------------- ------- -------- ---------------
- Standard_B1ms Burstable 1 2 GiB 640e
- ```
+1. Open the sidebar of `GITHUB COPILOT APP MODERNIZATION`. In **Tasks** view, click the **Run Task** button of **Java** -> **Deployment Tasks** -> **Provision Infrastructure and Deploy to Azure**.
-You can either run the deployment script locally or use the GitHub Codespaces. The recommended approach is to run the deployment script in the GitHub Codespaces, as it provides a ready-to-use environment with all the necessary dependencies.
+ 
+1. A predefined prompt will be populated in the Copilot Chat panel with Agent Mode. The default hosting Azure service is Azure Container Apps.To change the hosting service to **Azure Kubernetes Service** (AKS), click on the prompt in the Copilot Chat panel and edit the last sentence of the prompt to **Hosting service: AKS**.
-Deploy using GitHub Codespaces:
-1. Commit and push the changes to your forked repository.
-1. Follow instructions in [Use GitHub Codespaces for Deployment](README.md#use-github-codespaces-for-deployment) to deploy the app to Azure.
+ 
+1. Click ****Continue**/**Allow** if pop-up notifications to let Copilot Agent analyze the project and create a deployment plan in **plan.copilotmd** with Azure resources architecture, recommended Azure resources for project and security configurations, and execution steps for deployment.
-Deploy using local environment by running the deployment script in the terminal:
-1. Run `az login` to sign in to Azure.
-1. Run the following commands to deploy the app to Azure:
+1. View the architecture diagram, resource configurations, and execution steps in the plan. Click **Keep** to save the plan and type in **Execute the plan** to start the deployment.
- Windows:
- ```batch
- scripts\deploy-to-azure.cmd -ResourceGroupName -Location -Prefix
- ```
+ 
+1. When prompted, click **Continue**/**Allow** in chat notifications or type **y**/**yes** in terminal as Copilot Agent follows the plan and leverages agent tools to create and run provisioning and deployment scripts, fix potential errors, and finish the deployment. You can also check the deployment status in **progress.copilotmd**. **DO NOT interrupt** when provisioning or deployment scripts are running.
- Linux:
- ```bash
- scripts/deploy-to-azure.sh -ResourceGroupName -Location -Prefix
- ```
+ 
-Once the deployment script completes successfully, it outputs the URL of the Web application. Open the URL in a browser to verify if the application is running as expected.
+> Note: If you encounter any issues with the deployment step, you can refer to the expected Copilot-generated deployment scripts in `/.azure` folder of the [workshop/deployment-expected](https://github.com/Azure-Samples/java-migration-copilot-samples/tree/workshop/deployment-expected/asset-manager) branch to compare your deployment scripts and troubleshoot the problems.
-## Clean up
+#### Clean up
-When no longer needed, you can delete all related resources using the following scripts.
+When no longer needed, you can delete all related resources using the following scripts.
Windows:
```batch
diff --git a/asset-manager/doc-media/containerization-execution-steps.png b/asset-manager/doc-media/containerization-execution-steps.png
new file mode 100644
index 0000000..40c5f5b
Binary files /dev/null and b/asset-manager/doc-media/containerization-execution-steps.png differ
diff --git a/asset-manager/doc-media/containerization-plan.png b/asset-manager/doc-media/containerization-plan.png
new file mode 100644
index 0000000..03d7202
Binary files /dev/null and b/asset-manager/doc-media/containerization-plan.png differ
diff --git a/asset-manager/doc-media/containerization-run-task.png b/asset-manager/doc-media/containerization-run-task.png
new file mode 100644
index 0000000..1bc461e
Binary files /dev/null and b/asset-manager/doc-media/containerization-run-task.png differ
diff --git a/asset-manager/doc-media/deployment-aks-prompt.png b/asset-manager/doc-media/deployment-aks-prompt.png
new file mode 100644
index 0000000..8b479bb
Binary files /dev/null and b/asset-manager/doc-media/deployment-aks-prompt.png differ
diff --git a/asset-manager/doc-media/deployment-architecure.png b/asset-manager/doc-media/deployment-architecure.png
new file mode 100644
index 0000000..d4e27fc
Binary files /dev/null and b/asset-manager/doc-media/deployment-architecure.png differ
diff --git a/asset-manager/doc-media/deployment-default-prompt.png b/asset-manager/doc-media/deployment-default-prompt.png
new file mode 100644
index 0000000..05ae928
Binary files /dev/null and b/asset-manager/doc-media/deployment-default-prompt.png differ
diff --git a/asset-manager/doc-media/deployment-execute.png b/asset-manager/doc-media/deployment-execute.png
new file mode 100644
index 0000000..a63340d
Binary files /dev/null and b/asset-manager/doc-media/deployment-execute.png differ
diff --git a/asset-manager/doc-media/deployment-progress.png b/asset-manager/doc-media/deployment-progress.png
new file mode 100644
index 0000000..3e30d0c
Binary files /dev/null and b/asset-manager/doc-media/deployment-progress.png differ
diff --git a/asset-manager/doc-media/deployment-prompt.png b/asset-manager/doc-media/deployment-prompt.png
new file mode 100644
index 0000000..fc9516b
Binary files /dev/null and b/asset-manager/doc-media/deployment-prompt.png differ
diff --git a/asset-manager/doc-media/deployment-run-task.png b/asset-manager/doc-media/deployment-run-task.png
new file mode 100644
index 0000000..dadafdf
Binary files /dev/null and b/asset-manager/doc-media/deployment-run-task.png differ
diff --git a/asset-manager/doc-media/health-endpoint-task.png b/asset-manager/doc-media/health-endpoint-task.png
new file mode 100644
index 0000000..e731813
Binary files /dev/null and b/asset-manager/doc-media/health-endpoint-task.png differ
diff --git a/asset-manager/doc-media/java-upgrade-button.png b/asset-manager/doc-media/java-upgrade-button.png
new file mode 100644
index 0000000..421197f
Binary files /dev/null and b/asset-manager/doc-media/java-upgrade-button.png differ
diff --git a/asset-manager/doc-media/java-upgrade.png b/asset-manager/doc-media/java-upgrade.png
new file mode 100644
index 0000000..10343b7
Binary files /dev/null and b/asset-manager/doc-media/java-upgrade.png differ
diff --git a/asset-manager/doc-media/trigger-assessment.png b/asset-manager/doc-media/trigger-assessment.png
index 7f16bad..8cd8c55 100644
Binary files a/asset-manager/doc-media/trigger-assessment.png and b/asset-manager/doc-media/trigger-assessment.png differ
diff --git a/asset-manager/pom.xml b/asset-manager/pom.xml
index f46b46d..33450fb 100644
--- a/asset-manager/pom.xml
+++ b/asset-manager/pom.xml
@@ -6,7 +6,7 @@
org.springframework.bootspring-boot-starter-parent
- 3.4.3
+ 2.7.18
@@ -16,7 +16,7 @@
pom
- 21
+ 8
diff --git a/asset-manager/scripts/startapp.cmd b/asset-manager/scripts/startapp.cmd
new file mode 100644
index 0000000..716bc35
--- /dev/null
+++ b/asset-manager/scripts/startapp.cmd
@@ -0,0 +1,32 @@
+@echo off
+setlocal
+
+rem Get the directory where the script is located
+set SCRIPT_DIR=%~dp0
+set PROJECT_ROOT=%SCRIPT_DIR%..
+
+echo Starting PostgreSQL container...
+docker run -d --name assets-postgres -e POSTGRES_DB=assets_manager -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres -p 5432:5432 postgres:latest
+
+echo Starting RabbitMQ container...
+docker run -d --name assets-rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:management
+
+echo Waiting for services to start...
+timeout /t 10 /nobreak
+
+rem Create logs directory if it doesn't exist
+if not exist "%PROJECT_ROOT%\logs" mkdir "%PROJECT_ROOT%\logs"
+
+rem Create pids directory if it doesn't exist
+if not exist "%PROJECT_ROOT%\pids" mkdir "%PROJECT_ROOT%\pids"
+
+echo Starting web module...
+cd /d "%PROJECT_ROOT%\web"
+start "Web Module" cmd /k "%PROJECT_ROOT%\mvnw.cmd clean spring-boot:run -Dspring-boot.run.jvmArguments=-Dspring.pid.file=%PROJECT_ROOT%\pids\web.pid -Dspring-boot.run.profiles=dev"
+
+echo Starting worker module...
+cd /d "%PROJECT_ROOT%\worker"
+start "Worker Module" cmd /k "%PROJECT_ROOT%\mvnw.cmd clean spring-boot:run -Dspring-boot.run.jvmArguments=-Dspring.pid.file=%PROJECT_ROOT%\pids\worker.pid -Dspring-boot.run.profiles=dev"
+
+echo Web application: http://localhost:8080
+echo RabbitMQ Management: http://localhost:15672 (guest/guest)
diff --git a/asset-manager/scripts/startapp.sh b/asset-manager/scripts/startapp.sh
new file mode 100755
index 0000000..62ad611
--- /dev/null
+++ b/asset-manager/scripts/startapp.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+# Get the directory where the script is located
+SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+PROJECT_ROOT="$SCRIPT_DIR/.."
+
+echo "Starting PostgreSQL container..."
+docker run -d --name assets-postgres \
+ -e POSTGRES_DB=assets_manager \
+ -e POSTGRES_USER=postgres \
+ -e POSTGRES_PASSWORD=postgres \
+ -p 5432:5432 postgres:latest
+
+echo "Starting RabbitMQ container..."
+docker run -d --name assets-rabbitmq \
+ -p 5672:5672 \
+ -p 15672:15672 \
+ rabbitmq:management
+
+echo "Waiting for services to start..."
+sleep 10
+
+# Create logs directory if it doesn't exist
+mkdir -p "$PROJECT_ROOT/logs"
+
+# Create pids directory if it doesn't exist
+mkdir -p "$PROJECT_ROOT/pids"
+
+echo "Starting web module..."
+cd "$PROJECT_ROOT/web" && "$PROJECT_ROOT/mvnw" clean spring-boot:run -Dspring-boot.run.jvmArguments="-Dspring.pid.file=$PROJECT_ROOT/pids/web.pid" -Dspring-boot.run.profiles=dev > "$PROJECT_ROOT/logs/web.log" 2>&1 &
+
+echo "Starting worker module..."
+cd "$PROJECT_ROOT/worker" && "$PROJECT_ROOT/mvnw" clean spring-boot:run -Dspring-boot.run.jvmArguments="-Dspring.pid.file=$PROJECT_ROOT/pids/worker.pid" -Dspring-boot.run.profiles=dev > "$PROJECT_ROOT/logs/worker.log" 2>&1 &
+
+echo "All services started! Check logs directory for output."
+echo "Web application: http://localhost:8080"
+echo "RabbitMQ Management: http://localhost:15672 (guest/guest)"
\ No newline at end of file
diff --git a/asset-manager/scripts/stopapp.cmd b/asset-manager/scripts/stopapp.cmd
new file mode 100644
index 0000000..7c62abd
--- /dev/null
+++ b/asset-manager/scripts/stopapp.cmd
@@ -0,0 +1,73 @@
+@echo off
+setlocal enabledelayedexpansion
+
+rem Get the directory where the script is located
+set SCRIPT_DIR=%~dp0
+set PROJECT_ROOT=%SCRIPT_DIR%..
+
+echo Stopping Java processes...
+
+rem Check if web PID file exists and stop the process
+if exist "%PROJECT_ROOT%\pids\web.pid" (
+ set /p WEB_PID=<"%PROJECT_ROOT%\pids\web.pid"
+ call :trim WEB_PID
+ if defined WEB_PID (
+ if !WEB_PID! GTR 0 (
+ echo Stopping web module with PID: !WEB_PID!
+ taskkill /F /PID !WEB_PID! 2>nul
+ if !ERRORLEVEL! EQU 0 (
+ echo Web process successfully stopped.
+ ) else (
+ echo Failed to stop web process, it may have already terminated.
+ )
+ ) else (
+ echo Invalid web PID found in file.
+ )
+ ) else (
+ echo Empty web PID file found.
+ )
+ del "%PROJECT_ROOT%\pids\web.pid"
+) else (
+ echo Web PID file not found, the service may not be running.
+)
+
+rem Check if worker PID file exists and stop the process
+if exist "%PROJECT_ROOT%\pids\worker.pid" (
+ set /p WORKER_PID=<"%PROJECT_ROOT%\pids\worker.pid"
+ call :trim WORKER_PID
+ if defined WORKER_PID (
+ if !WORKER_PID! GTR 0 (
+ echo Stopping worker module with PID: !WORKER_PID!
+ taskkill /F /PID !WORKER_PID! 2>nul
+ if !ERRORLEVEL! EQU 0 (
+ echo Worker process successfully stopped.
+ ) else (
+ echo Failed to stop worker process, it may have already terminated.
+ )
+ ) else (
+ echo Invalid worker PID found in file.
+ )
+ ) else (
+ echo Empty worker PID file found.
+ )
+ del "%PROJECT_ROOT%\pids\worker.pid"
+) else (
+ echo Worker PID file not found, the service may not be running.
+)
+
+echo Stopping and removing Docker containers...
+docker stop assets-postgres assets-rabbitmq 2>nul
+docker rm assets-postgres assets-rabbitmq 2>nul
+
+echo All services stopped!
+goto :eof
+
+:trim
+rem Remove leading and trailing whitespace from variable
+setlocal enabledelayedexpansion
+set "var=!%1!"
+for /f "tokens=* delims= " %%a in ("!var!") do set "var=%%a"
+:loop
+if "!var:~-1!"==" " set "var=!var:~0,-1!" & goto loop
+endlocal & set "%1=%var%"
+goto :eof
diff --git a/asset-manager/scripts/stopapp.sh b/asset-manager/scripts/stopapp.sh
new file mode 100755
index 0000000..abfd9b7
--- /dev/null
+++ b/asset-manager/scripts/stopapp.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+# Get the directory where the script is located
+SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+PROJECT_ROOT="$SCRIPT_DIR/.."
+
+echo "Stopping Java processes..."
+
+# Check if web PID file exists and stop the process
+if [ -f "$PROJECT_ROOT/pids/web.pid" ]; then
+ WEB_PID=$(cat "$PROJECT_ROOT/pids/web.pid")
+ echo "Stopping web module with PID: $WEB_PID"
+ kill -9 $WEB_PID 2>/dev/null || echo "Process not found"
+ rm "$PROJECT_ROOT/pids/web.pid"
+else
+ echo "Web PID file not found, the service may not be running."
+fi
+
+# Check if worker PID file exists and stop the process
+if [ -f "$PROJECT_ROOT/pids/worker.pid" ]; then
+ WORKER_PID=$(cat "$PROJECT_ROOT/pids/worker.pid")
+ echo "Stopping worker module with PID: $WORKER_PID"
+ kill -9 $WORKER_PID 2>/dev/null || echo "Process not found"
+ rm "$PROJECT_ROOT/pids/worker.pid"
+else
+ echo "Worker PID file not found, the service may not be running."
+fi
+
+echo "Stopping and removing Docker containers..."
+docker stop assets-postgres assets-rabbitmq 2>/dev/null
+docker rm assets-postgres assets-rabbitmq 2>/dev/null
+
+echo "All services stopped!"
\ No newline at end of file
diff --git a/asset-manager/web/pom.xml b/asset-manager/web/pom.xml
index 3b9228f..59fcccd 100644
--- a/asset-manager/web/pom.xml
+++ b/asset-manager/web/pom.xml
@@ -11,7 +11,6 @@
2.25.13
- 5.19.0assets-manager-web
@@ -28,22 +27,12 @@
spring-boot-starter-web
- com.azure.spring
- spring-cloud-azure-starter
-
-
- com.azure.spring
- spring-messaging-azure-servicebus
-
-
- com.azure
- azure-storage-blob
- 12.29.0
+ org.springframework.boot
+ spring-boot-starter-amqp
- com.azure
- azure-identity
- 1.14.2
+ software.amazon.awssdk
+ s3org.springframework.boot
@@ -80,17 +69,10 @@
- com.azure
- azure-storage-blob-batch
- 12.25.0
+ software.amazon.awssdk
+ s3
+ ${aws-sdk.version}
-
- com.azure.spring
- spring-cloud-azure-dependencies
- ${version.spring.cloud.azure}
- pom
- import
-
diff --git a/asset-manager/web/src/main/java/com/microsoft/migration/assets/AssetsManagerApplication.java b/asset-manager/web/src/main/java/com/microsoft/migration/assets/AssetsManagerApplication.java
index 265245f..6b264ad 100644
--- a/asset-manager/web/src/main/java/com/microsoft/migration/assets/AssetsManagerApplication.java
+++ b/asset-manager/web/src/main/java/com/microsoft/migration/assets/AssetsManagerApplication.java
@@ -1,12 +1,12 @@
package com.microsoft.migration.assets;
-import com.azure.spring.messaging.implementation.annotation.EnableAzureMessaging;
+import org.springframework.amqp.rabbit.annotation.EnableRabbit;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.ApplicationPidFileWriter;
@SpringBootApplication
-@EnableAzureMessaging
+@EnableRabbit
public class AssetsManagerApplication {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(AssetsManagerApplication.class);
diff --git a/asset-manager/web/src/main/java/com/microsoft/migration/assets/config/AwsS3Config.java b/asset-manager/web/src/main/java/com/microsoft/migration/assets/config/AwsS3Config.java
index 4a94696..0e16fd8 100644
--- a/asset-manager/web/src/main/java/com/microsoft/migration/assets/config/AwsS3Config.java
+++ b/asset-manager/web/src/main/java/com/microsoft/migration/assets/config/AwsS3Config.java
@@ -1,23 +1,31 @@
package com.microsoft.migration.assets.config;
-import com.azure.identity.DefaultAzureCredentialBuilder;
-import com.azure.storage.blob.BlobServiceClient;
-import com.azure.storage.blob.BlobServiceClientBuilder;
import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
+import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
+import software.amazon.awssdk.regions.Region;
+import software.amazon.awssdk.services.s3.S3Client;
+
@Configuration
public class AwsS3Config {
- @Value("${azure.storage.account-name}")
- private String accountName;
+ @Value("${aws.accessKey}")
+ private String accessKey;
+
+ @Value("${aws.secretKey}")
+ private String secretKey;
+
+ @Value("${aws.region}")
+ private String region;
- @Bean
- public BlobServiceClient blobServiceClient() {
- return new BlobServiceClientBuilder()
- .endpoint("https://" + accountName + ".blob.core.windows.net")
- .credential(new DefaultAzureCredentialBuilder().build())
- .buildClient();
+ public S3Client s3Client() {
+ AwsBasicCredentials awsCredentials = AwsBasicCredentials.create(accessKey, secretKey);
+
+ return S3Client.builder()
+ .region(Region.of(region))
+ .credentialsProvider(StaticCredentialsProvider.create(awsCredentials))
+ .build();
}
}
\ No newline at end of file
diff --git a/asset-manager/web/src/main/java/com/microsoft/migration/assets/config/RabbitConfig.java b/asset-manager/web/src/main/java/com/microsoft/migration/assets/config/RabbitConfig.java
index 9d9d60d..d42619b 100644
--- a/asset-manager/web/src/main/java/com/microsoft/migration/assets/config/RabbitConfig.java
+++ b/asset-manager/web/src/main/java/com/microsoft/migration/assets/config/RabbitConfig.java
@@ -1,84 +1,40 @@
package com.microsoft.migration.assets.config;
-import com.azure.core.credential.TokenCredential;
-import com.azure.core.exception.ResourceExistsException;
-import com.azure.core.exception.ResourceNotFoundException;
-import com.azure.messaging.servicebus.administration.ServiceBusAdministrationClient;
-import com.azure.messaging.servicebus.administration.ServiceBusAdministrationClientBuilder;
-import com.azure.messaging.servicebus.administration.models.CreateQueueOptions;
-import com.azure.messaging.servicebus.administration.models.QueueProperties;
-import com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusProperties;
-import com.azure.spring.messaging.ConsumerIdentifier;
-import com.azure.spring.messaging.PropertiesSupplier;
-import com.azure.spring.messaging.servicebus.core.properties.ProcessorProperties;
+import org.springframework.amqp.core.AcknowledgeMode;
+import org.springframework.amqp.core.Queue;
+import org.springframework.amqp.core.QueueBuilder;
+import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
+import org.springframework.amqp.rabbit.connection.ConnectionFactory;
+import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
+import org.springframework.amqp.support.converter.MessageConverter;
+import org.springframework.boot.autoconfigure.amqp.SimpleRabbitListenerContainerFactoryConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import java.time.Duration;
-
@Configuration
public class RabbitConfig {
public static final String IMAGE_PROCESSING_QUEUE = "image-processing";
- public static final String RETRY_QUEUE = "retry-queue";
- public static final Duration RETRY_QUEUE_TTL = Duration.ofMinutes(1);
@Bean
- public ServiceBusAdministrationClient adminClient(AzureServiceBusProperties properties, TokenCredential credential) {
- return new ServiceBusAdministrationClientBuilder()
- .credential(properties.getFullyQualifiedNamespace(), credential)
- .buildClient();
+ public Queue imageProcessingQueue() {
+ return QueueBuilder.durable(IMAGE_PROCESSING_QUEUE)
+ .build();
}
@Bean
- public QueueProperties retryQueue(ServiceBusAdministrationClient adminClient) {
- try {
- return adminClient.getQueue(RETRY_QUEUE);
- } catch (ResourceNotFoundException e) {
- try {
- CreateQueueOptions options = new CreateQueueOptions()
- .setDefaultMessageTimeToLive(RETRY_QUEUE_TTL)
- .setDeadLetteringOnMessageExpiration(true);
- return adminClient.createQueue(RETRY_QUEUE, options);
- } catch (ResourceExistsException ex) {
- // Queue was created by another instance in the meantime
- return adminClient.getQueue(RETRY_QUEUE);
- }
- }
+ public MessageConverter jsonMessageConverter() {
+ return new Jackson2JsonMessageConverter();
}
@Bean
- public QueueProperties imageProcessingQueue(ServiceBusAdministrationClient adminClient, QueueProperties retryQueue) {
- QueueProperties queue;
- try {
- queue = adminClient.getQueue(IMAGE_PROCESSING_QUEUE);
- } catch (ResourceNotFoundException e) {
- try {
- CreateQueueOptions options = new CreateQueueOptions()
- .setForwardDeadLetteredMessagesTo(RETRY_QUEUE);
- queue = adminClient.createQueue(IMAGE_PROCESSING_QUEUE, options);
- } catch (ResourceExistsException ex) {
- // Queue was created by another instance in the meantime
- queue = adminClient.getQueue(IMAGE_PROCESSING_QUEUE);
- }
- }
-
- // Configure retry queue's DLQ forwarding now that image processing queue exists
- try {
- retryQueue.setForwardDeadLetteredMessagesTo(IMAGE_PROCESSING_QUEUE);
- adminClient.updateQueue(retryQueue);
- } catch (Exception ex) {
- // Ignore update errors since basic functionality will still work
- }
-
- return queue;
+ public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(
+ ConnectionFactory connectionFactory,
+ SimpleRabbitListenerContainerFactoryConfigurer configurer) {
+ SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
+ configurer.configure(factory, connectionFactory);
+ factory.setMessageConverter(jsonMessageConverter());
+ factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);
+ return factory;
}
- @Bean
- public PropertiesSupplier propertiesSupplier() {
- return identifier -> {
- ProcessorProperties processorProperties = new ProcessorProperties();
- processorProperties.setAutoComplete(false);
- return processorProperties;
- };
- }
-}
+}
\ No newline at end of file
diff --git a/asset-manager/web/src/main/java/com/microsoft/migration/assets/config/WebMvcConfig.java b/asset-manager/web/src/main/java/com/microsoft/migration/assets/config/WebMvcConfig.java
new file mode 100644
index 0000000..af668e1
--- /dev/null
+++ b/asset-manager/web/src/main/java/com/microsoft/migration/assets/config/WebMvcConfig.java
@@ -0,0 +1,100 @@
+package com.microsoft.migration.assets.config;
+
+import com.microsoft.migration.assets.constants.StorageConstants;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.CacheControl;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
+import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.concurrent.TimeUnit;
+
+@Configuration
+@SuppressWarnings("deprecation")
+public class WebMvcConfig extends WebMvcConfigurerAdapter {
+
+ /**
+ * Resource handlers with caching for static content.
+ */
+ @Override
+ public void addResourceHandlers(ResourceHandlerRegistry registry) {
+ // Add cache control for CSS, JS, and image files
+ registry.addResourceHandler("/css/**", "/js/**", "/images/**")
+ .addResourceLocations("classpath:/static/css/", "classpath:/static/js/", "classpath:/static/images/")
+ .setCacheControl(CacheControl.maxAge(30, TimeUnit.DAYS).cachePublic());
+
+ // Add cache control for favicon
+ registry.addResourceHandler("/favicon.ico")
+ .addResourceLocations("classpath:/static/")
+ .setCacheControl(CacheControl.maxAge(7, TimeUnit.DAYS).cachePublic());
+ }
+
+ /**
+ * Interceptors for request logging and file operation monitoring.
+ */
+ @Override
+ public void addInterceptors(InterceptorRegistry registry) {
+ registry.addInterceptor(new FileOperationLoggingInterceptor())
+ .addPathPatterns("/" + StorageConstants.STORAGE_PATH + "/**")
+ .excludePathPatterns("/" + StorageConstants.STORAGE_PATH + "/view/**"); // Exclude file download endpoints from detailed logging
+ }
+
+ /**
+ * Custom interceptor using HandlerInterceptorAdapter.
+ * This interceptor logs file operations for monitoring and debugging purposes.
+ */
+ private static class FileOperationLoggingInterceptor extends HandlerInterceptorAdapter {
+
+ @Override
+ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
+ long startTime = System.currentTimeMillis();
+ request.setAttribute("startTime", startTime);
+
+ String operation = determineFileOperation(request);
+ System.out.printf("[FILE-OP] %s %s - %s started at %d%n",
+ request.getMethod(), request.getRequestURI(), operation, startTime);
+
+ return true;
+ }
+
+ @Override
+ public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
+ Object handler, Exception ex) {
+ long startTime = (Long) request.getAttribute("startTime");
+ long duration = System.currentTimeMillis() - startTime;
+ String operation = determineFileOperation(request);
+
+ if (ex != null) {
+ System.out.printf("[FILE-OP] %s %s - %s FAILED in %d ms (Status: %d, Error: %s)%n",
+ request.getMethod(), request.getRequestURI(), operation, duration,
+ response.getStatus(), ex.getMessage());
+ } else {
+ System.out.printf("[FILE-OP] %s %s - %s completed in %d ms (Status: %d)%n",
+ request.getMethod(), request.getRequestURI(), operation, duration,
+ response.getStatus());
+ }
+ }
+
+ private String determineFileOperation(HttpServletRequest request) {
+ String uri = request.getRequestURI();
+ String method = request.getMethod();
+
+ if (uri.contains("/upload")) {
+ return "FILE_UPLOAD";
+ } else if (uri.contains("/delete/")) {
+ return "FILE_DELETE";
+ } else if (uri.contains("/view/")) {
+ return "FILE_DOWNLOAD";
+ } else if (uri.contains("/view-page/")) {
+ return "FILE_VIEW_PAGE";
+ } else if ("GET".equals(method) && uri.equals("/" + StorageConstants.STORAGE_PATH)) {
+ return "FILE_LIST";
+ } else {
+ return "FILE_OPERATION";
+ }
+ }
+ }
+}
diff --git a/asset-manager/web/src/main/java/com/microsoft/migration/assets/constants/StorageConstants.java b/asset-manager/web/src/main/java/com/microsoft/migration/assets/constants/StorageConstants.java
new file mode 100644
index 0000000..2c5c69a
--- /dev/null
+++ b/asset-manager/web/src/main/java/com/microsoft/migration/assets/constants/StorageConstants.java
@@ -0,0 +1,16 @@
+package com.microsoft.migration.assets.constants;
+
+/**
+ * Application constants for storage paths and configurations
+ */
+public final class StorageConstants {
+
+ /**
+ * Base storage path for web endpoints
+ */
+ public static final String STORAGE_PATH = "storage";
+
+ private StorageConstants() {
+ // Utility class - prevent instantiation
+ }
+}
\ No newline at end of file
diff --git a/asset-manager/web/src/main/java/com/microsoft/migration/assets/controller/HomeController.java b/asset-manager/web/src/main/java/com/microsoft/migration/assets/controller/HomeController.java
index 87cfdb4..36841a3 100644
--- a/asset-manager/web/src/main/java/com/microsoft/migration/assets/controller/HomeController.java
+++ b/asset-manager/web/src/main/java/com/microsoft/migration/assets/controller/HomeController.java
@@ -1,5 +1,6 @@
package com.microsoft.migration.assets.controller;
+import com.microsoft.migration.assets.constants.StorageConstants;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@@ -8,6 +9,6 @@ public class HomeController {
@GetMapping("/")
public String home() {
- return "redirect:/s3";
+ return "redirect:/" + StorageConstants.STORAGE_PATH;
}
}
\ No newline at end of file
diff --git a/asset-manager/web/src/main/java/com/microsoft/migration/assets/controller/S3Controller.java b/asset-manager/web/src/main/java/com/microsoft/migration/assets/controller/S3Controller.java
index bfb4a3b..e9fbc06 100644
--- a/asset-manager/web/src/main/java/com/microsoft/migration/assets/controller/S3Controller.java
+++ b/asset-manager/web/src/main/java/com/microsoft/migration/assets/controller/S3Controller.java
@@ -1,5 +1,6 @@
package com.microsoft.migration.assets.controller;
+import com.microsoft.migration.assets.constants.StorageConstants;
import com.microsoft.migration.assets.model.S3StorageItem;
import com.microsoft.migration.assets.service.StorageService;
import lombok.RequiredArgsConstructor;
@@ -19,7 +20,7 @@
import java.util.Optional;
@Controller
-@RequestMapping("/s3")
+@RequestMapping("/" + StorageConstants.STORAGE_PATH)
@RequiredArgsConstructor
public class S3Controller {
@@ -42,15 +43,15 @@ public String uploadObject(@RequestParam("file") MultipartFile file, RedirectAtt
try {
if (file.isEmpty()) {
redirectAttributes.addFlashAttribute("error", "Please select a file to upload");
- return "redirect:/s3/upload";
+ return "redirect:/" + StorageConstants.STORAGE_PATH + "/upload";
}
storageService.uploadObject(file);
redirectAttributes.addFlashAttribute("success", "File uploaded successfully");
- return "redirect:/s3";
+ return "redirect:/" + StorageConstants.STORAGE_PATH;
} catch (IOException e) {
redirectAttributes.addFlashAttribute("error", "Failed to upload file: " + e.getMessage());
- return "redirect:/s3/upload";
+ return "redirect:/" + StorageConstants.STORAGE_PATH + "/upload";
}
}
@@ -67,11 +68,11 @@ public String viewObjectPage(@PathVariable String key, Model model, RedirectAttr
return "view";
} else {
redirectAttributes.addFlashAttribute("error", "Image not found");
- return "redirect:/s3";
+ return "redirect:/" + StorageConstants.STORAGE_PATH;
}
} catch (Exception e) {
redirectAttributes.addFlashAttribute("error", "Failed to view image: " + e.getMessage());
- return "redirect:/s3";
+ return "redirect:/" + StorageConstants.STORAGE_PATH;
}
}
@@ -100,6 +101,6 @@ public String deleteObject(@PathVariable String key, RedirectAttributes redirect
} catch (Exception e) {
redirectAttributes.addFlashAttribute("error", "Failed to delete file: " + e.getMessage());
}
- return "redirect:/s3";
+ return "redirect:/" + StorageConstants.STORAGE_PATH;
}
}
\ No newline at end of file
diff --git a/asset-manager/web/src/main/java/com/microsoft/migration/assets/model/ImageMetadata.java b/asset-manager/web/src/main/java/com/microsoft/migration/assets/model/ImageMetadata.java
index f6fe5be..97ae548 100644
--- a/asset-manager/web/src/main/java/com/microsoft/migration/assets/model/ImageMetadata.java
+++ b/asset-manager/web/src/main/java/com/microsoft/migration/assets/model/ImageMetadata.java
@@ -1,6 +1,6 @@
package com.microsoft.migration.assets.model;
-import jakarta.persistence.*;
+import javax.persistence.*;
import lombok.Data;
import lombok.NoArgsConstructor;
diff --git a/asset-manager/web/src/main/java/com/microsoft/migration/assets/service/AwsS3Service.java b/asset-manager/web/src/main/java/com/microsoft/migration/assets/service/AwsS3Service.java
index 033cdee..4e7875c 100644
--- a/asset-manager/web/src/main/java/com/microsoft/migration/assets/service/AwsS3Service.java
+++ b/asset-manager/web/src/main/java/com/microsoft/migration/assets/service/AwsS3Service.java
@@ -1,22 +1,18 @@
package com.microsoft.migration.assets.service;
-import com.azure.identity.DefaultAzureCredentialBuilder;
-import com.azure.storage.blob.BlobServiceClient;
-import com.azure.storage.blob.BlobServiceClientBuilder;
-import com.azure.storage.blob.models.BlobHttpHeaders;
-import com.azure.storage.blob.models.BlobItem;
-import com.azure.storage.blob.options.BlobParallelUploadOptions;
import com.microsoft.migration.assets.model.ImageMetadata;
import com.microsoft.migration.assets.model.ImageProcessingMessage;
import com.microsoft.migration.assets.model.S3StorageItem;
import com.microsoft.migration.assets.repository.ImageMetadataRepository;
import lombok.RequiredArgsConstructor;
-import com.azure.spring.messaging.servicebus.core.ServiceBusTemplate;
- import org.springframework.messaging.support.MessageBuilder;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
+import software.amazon.awssdk.core.sync.RequestBody;
+import software.amazon.awssdk.services.s3.S3Client;
+import software.amazon.awssdk.services.s3.model.*;
import java.io.IOException;
import java.io.InputStream;
@@ -32,31 +28,37 @@
@Profile("!dev") // Active when not in dev profile
public class AwsS3Service implements StorageService {
- private final BlobServiceClient blobServiceClient;
- private final ServiceBusTemplate serviceBusTemplate;
+ private final S3Client s3Client;
+ private final RabbitTemplate rabbitTemplate;
private final ImageMetadataRepository imageMetadataRepository;
- @Value("${azure.storage.blob.container-name}")
- private String containerName;
+ @Value("${aws.s3.bucket}")
+ private String bucketName;
@Override
public List listObjects() {
- return blobServiceClient.getBlobContainerClient(containerName).listBlobs().stream()
- .map(blobItem -> {
+ ListObjectsV2Request request = ListObjectsV2Request.builder()
+ .bucket(bucketName)
+ .build();
+
+ ListObjectsV2Response response = s3Client.listObjectsV2(request);
+
+ return response.contents().stream()
+ .map(s3Object -> {
// Try to get metadata for upload time
Instant uploadedAt = imageMetadataRepository.findAll().stream()
- .filter(metadata -> metadata.getS3Key().equals(blobItem.getName()))
+ .filter(metadata -> metadata.getS3Key().equals(s3Object.key()))
.map(metadata -> metadata.getUploadedAt().atZone(java.time.ZoneId.systemDefault()).toInstant())
.findFirst()
- .orElse(blobItem.getProperties().getLastModified().toInstant()); // fallback to lastModified if metadata not found
+ .orElse(s3Object.lastModified()); // fallback to lastModified if metadata not found
return new S3StorageItem(
- blobItem.getName(),
- extractFilename(blobItem.getName()),
- blobItem.getProperties().getContentLength(),
- blobItem.getProperties().getLastModified().toInstant(),
+ s3Object.key(),
+ extractFilename(s3Object.key()),
+ s3Object.size(),
+ s3Object.lastModified(),
uploadedAt,
- generateUrl(blobItem.getName())
+ generateUrl(s3Object.key())
);
})
.collect(Collectors.toList());
@@ -65,11 +67,13 @@ public List listObjects() {
@Override
public void uploadObject(MultipartFile file) throws IOException {
String key = generateKey(file.getOriginalFilename());
-
- var blobClient = blobServiceClient.getBlobContainerClient(containerName).getBlobClient(key);
- BlobHttpHeaders headers = new BlobHttpHeaders().setContentType(file.getContentType());
- BlobParallelUploadOptions options = new BlobParallelUploadOptions(file.getInputStream()).setHeaders(headers);
- blobClient.uploadWithResponse(options, null, null);
+ PutObjectRequest request = PutObjectRequest.builder()
+ .bucket(bucketName)
+ .key(key)
+ .contentType(file.getContentType())
+ .build();
+
+ s3Client.putObject(request, RequestBody.fromInputStream(file.getInputStream(), file.getSize()));
// Send message to queue for thumbnail generation
ImageProcessingMessage message = new ImageProcessingMessage(
@@ -78,7 +82,7 @@ public void uploadObject(MultipartFile file) throws IOException {
getStorageType(),
file.getSize()
);
- serviceBusTemplate.send(IMAGE_PROCESSING_QUEUE, MessageBuilder.withPayload(message).build());
+ rabbitTemplate.convertAndSend(IMAGE_PROCESSING_QUEUE, message);
// Create and save metadata to database
ImageMetadata metadata = new ImageMetadata();
@@ -94,23 +98,31 @@ public void uploadObject(MultipartFile file) throws IOException {
@Override
public InputStream getObject(String key) throws IOException {
- return blobServiceClient.getBlobContainerClient(containerName)
- .getBlobClient(key)
- .openInputStream();
+ GetObjectRequest request = GetObjectRequest.builder()
+ .bucket(bucketName)
+ .key(key)
+ .build();
+
+ return s3Client.getObject(request);
}
@Override
public void deleteObject(String key) throws IOException {
// Delete both original and thumbnail if it exists
- blobServiceClient.getBlobContainerClient(containerName)
- .getBlobClient(key)
- .delete();
+ DeleteObjectRequest request = DeleteObjectRequest.builder()
+ .bucket(bucketName)
+ .key(key)
+ .build();
+
+ s3Client.deleteObject(request);
try {
// Try to delete thumbnail if it exists
- blobServiceClient.getBlobContainerClient(containerName)
- .getBlobClient(getThumbnailKey(key))
- .delete();
+ DeleteObjectRequest thumbnailRequest = DeleteObjectRequest.builder()
+ .bucket(bucketName)
+ .key(getThumbnailKey(key))
+ .build();
+ s3Client.deleteObject(thumbnailRequest);
} catch (Exception e) {
// Ignore if thumbnail doesn't exist
}
@@ -124,7 +136,7 @@ public void deleteObject(String key) throws IOException {
@Override
public String getStorageType() {
- return "azure";
+ return "s3";
}
private String extractFilename(String key) {
@@ -133,12 +145,6 @@ private String extractFilename(String key) {
return lastSlashIndex >= 0 ? key.substring(lastSlashIndex + 1) : key;
}
- private String generateUrl(String key) {
- return blobServiceClient.getBlobContainerClient(containerName)
- .getBlobClient(key)
- .getBlobUrl();
- }
-
private String generateKey(String filename) {
return UUID.randomUUID().toString() + "-" + filename;
}
diff --git a/asset-manager/web/src/main/java/com/microsoft/migration/assets/service/BackupMessageProcessor.java b/asset-manager/web/src/main/java/com/microsoft/migration/assets/service/BackupMessageProcessor.java
index c9c9c90..13e584e 100644
--- a/asset-manager/web/src/main/java/com/microsoft/migration/assets/service/BackupMessageProcessor.java
+++ b/asset-manager/web/src/main/java/com/microsoft/migration/assets/service/BackupMessageProcessor.java
@@ -1,16 +1,17 @@
package com.microsoft.migration.assets.service;
import com.microsoft.migration.assets.model.ImageProcessingMessage;
-import com.azure.spring.messaging.servicebus.implementation.core.annotation.ServiceBusListener;
-import com.azure.messaging.servicebus.ServiceBusReceivedMessageContext;
-import com.azure.spring.messaging.servicebus.support.ServiceBusMessageHeaders;
+import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
+import org.springframework.amqp.rabbit.annotation.RabbitListener;
+import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
import static com.microsoft.migration.assets.config.RabbitConfig.IMAGE_PROCESSING_QUEUE;
+import java.io.IOException;
/**
* A backup message processor that serves as a monitoring and logging service.
@@ -24,28 +25,28 @@ public class BackupMessageProcessor {
/**
* Processes image messages from a backup queue for monitoring and resilience purposes.
- * Uses the same Azure Service Bus API pattern as the worker module.
+ * Uses the same RabbitMQ API pattern as the worker module.
*/
- @ServiceBusListener(destination = IMAGE_PROCESSING_QUEUE)
+ @RabbitListener(queues = IMAGE_PROCESSING_QUEUE)
public void processBackupMessage(final ImageProcessingMessage message,
- @Header(ServiceBusMessageHeaders.RECEIVED_MESSAGE_CONTEXT) ServiceBusReceivedMessageContext context) {
-
+ Channel channel,
+ @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) {
try {
log.info("[BACKUP] Monitoring message: {}", message.getKey());
log.info("[BACKUP] Content type: {}, Storage: {}, Size: {}",
message.getContentType(), message.getStorageType(), message.getSize());
// Acknowledge the message
- context.complete();
+ channel.basicAck(deliveryTag, false);
log.info("[BACKUP] Successfully processed message: {}", message.getKey());
} catch (Exception e) {
log.error("[BACKUP] Failed to process message: " + message.getKey(), e);
try {
- // Reject the message and dead letter it
- context.deadLetter();
+ // Reject the message and requeue it
+ channel.basicNack(deliveryTag, false, true);
log.warn("[BACKUP] Message requeued: {}", message.getKey());
- } catch (Exception ackEx) {
+ } catch (IOException ackEx) {
log.error("[BACKUP] Error handling RabbitMQ acknowledgment: {}", message.getKey(), ackEx);
}
}
diff --git a/asset-manager/web/src/main/java/com/microsoft/migration/assets/service/LocalFileStorageService.java b/asset-manager/web/src/main/java/com/microsoft/migration/assets/service/LocalFileStorageService.java
index 72dfc72..9b33232 100644
--- a/asset-manager/web/src/main/java/com/microsoft/migration/assets/service/LocalFileStorageService.java
+++ b/asset-manager/web/src/main/java/com/microsoft/migration/assets/service/LocalFileStorageService.java
@@ -4,15 +4,14 @@
import com.microsoft.migration.assets.model.S3StorageItem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.azure.spring.messaging.servicebus.core.ServiceBusTemplate;
-import org.springframework.messaging.support.MessageBuilder;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
-import jakarta.annotation.PostConstruct;
+import javax.annotation.PostConstruct;
import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
@@ -28,15 +27,15 @@ public class LocalFileStorageService implements StorageService {
private static final Logger logger = LoggerFactory.getLogger(LocalFileStorageService.class);
- private final ServiceBusTemplate serviceBusTemplate;
+ private final RabbitTemplate rabbitTemplate;
@Value("${local.storage.directory:../storage}")
private String storageDirectory;
private Path rootLocation;
- public LocalFileStorageService(ServiceBusTemplate serviceBusTemplate) {
- this.serviceBusTemplate = serviceBusTemplate;
+ public LocalFileStorageService(RabbitTemplate rabbitTemplate) {
+ this.rabbitTemplate = rabbitTemplate;
}
@PostConstruct
@@ -103,7 +102,7 @@ public void uploadObject(MultipartFile file) throws IOException {
getStorageType(),
file.getSize()
);
- serviceBusTemplate.send(IMAGE_PROCESSING_QUEUE, MessageBuilder.withPayload(message).build());
+ rabbitTemplate.convertAndSend(IMAGE_PROCESSING_QUEUE, message);
}
@Override
@@ -142,9 +141,4 @@ public void deleteObject(String key) throws IOException {
public String getStorageType() {
return "local";
}
-
- private String generateUrl(String key) {
- // Generate a URL for the object (simplified path)
- return "/s3/view/" + key;
- }
}
\ No newline at end of file
diff --git a/asset-manager/web/src/main/java/com/microsoft/migration/assets/service/StorageService.java b/asset-manager/web/src/main/java/com/microsoft/migration/assets/service/StorageService.java
index bfaa599..24d98e2 100644
--- a/asset-manager/web/src/main/java/com/microsoft/migration/assets/service/StorageService.java
+++ b/asset-manager/web/src/main/java/com/microsoft/migration/assets/service/StorageService.java
@@ -1,5 +1,7 @@
package com.microsoft.migration.assets.service;
+import com.microsoft.migration.assets.constants.StorageConstants;
+import com.microsoft.migration.assets.model.ImageProcessingMessage;
import com.microsoft.migration.assets.model.S3StorageItem;
import org.springframework.web.multipart.MultipartFile;
@@ -48,4 +50,11 @@ default String getThumbnailKey(String key) {
}
return key + "_thumbnail";
}
+
+ /**
+ * Generate a URL for viewing the object
+ */
+ default String generateUrl(String key) {
+ return "/" + StorageConstants.STORAGE_PATH + "/view/" + key;
+ }
}
\ No newline at end of file
diff --git a/asset-manager/web/src/main/resources/application.properties b/asset-manager/web/src/main/resources/application.properties
index 2a94f7e..bc4f78e 100644
--- a/asset-manager/web/src/main/resources/application.properties
+++ b/asset-manager/web/src/main/resources/application.properties
@@ -1,18 +1,20 @@
spring.application.name=assets-manager
-# Azure Blob Storage Configuration
-azure.storage.account-name=${AZURE_STORAGE_ACCOUNT_NAME}
-azure.storage.blob.container-name=${AZURE_STORAGE_BLOB_CONTAINER_NAME}
+# AWS S3 Configuration
+aws.accessKey=your-access-key
+aws.secretKey=your-secret-key
+aws.region=us-east-1
+aws.s3.bucket=your-bucket-name
# Max file size for uploads
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB
-#Servicebus
- spring.cloud.azure.credential.managed-identity-enabled=true
- spring.cloud.azure.credential.client-id=${AZURE_CLIENT_ID}
- spring.cloud.azure.servicebus.namespace=${AZURE_SERVICEBUS_NAMESPACE}
- spring.cloud.azure.servicebus.entity-type=queue
+# RabbitMQ Configuration
+spring.rabbitmq.host=localhost
+spring.rabbitmq.port=5672
+spring.rabbitmq.username=guest
+spring.rabbitmq.password=guest
# Database Configuration
spring.datasource.url=jdbc:postgresql://localhost:5432/assets_manager
diff --git a/asset-manager/web/src/main/resources/templates/layout.html b/asset-manager/web/src/main/resources/templates/layout.html
index 68129cc..64083dc 100644
--- a/asset-manager/web/src/main/resources/templates/layout.html
+++ b/asset-manager/web/src/main/resources/templates/layout.html
@@ -23,8 +23,8 @@