Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/mvnw text eol=lf
*.cmd text eol=crlf
*.cmd text eol=crlf
*.sh text eol=lf
12 changes: 11 additions & 1 deletion .github/workflows/unit-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Java CI with Maven

on:
pull_request:
branches: ["main", "master"]
branches: ["main"]

jobs:
build:
Expand All @@ -16,5 +16,15 @@ jobs:
java-version: '25'
distribution: 'temurin'
cache: maven
- name: Clone and build spring-base-commons
run: |
git clone --depth 1 https://github.com/vulinh64/spring-base-commons.git
cd spring-base-commons
mvn clean install
cd ..
- name: Copy commons artifact to local Maven repo
run: |
mkdir -p ~/.m2/repository/com/vulinh/spring-base-commons/1.0.0/
cp spring-base-commons/target/spring-base-commons-1.0.0.jar ~/.m2/repository/com/vulinh/spring-base-commons/1.0.0/spring-base-commons-1.0.0.jar
- name: Run unit tests
run: mvn clean verify
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ COPY pom.xml mvnw ./
COPY .mvn/ .mvn/
RUN chmod +x mvnw

# Download dependencies (will be cached if pom.xml doesn't change)
RUN ./mvnw dependency:go-offline
# Copy local dependency to the local Maven repository in the build stage
COPY build/spring-base-commons/target/spring-base-commons-1.0.0.jar /root/.m2/repository/com/vulinh/spring-base-commons/1.0.0/spring-base-commons-1.0.0.jar

# Copy source code
COPY src/ src/
Expand Down
35 changes: 30 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* [Table of Contents](#table-of-contents)
* [Running the Container Stack for Local Development](#running-the-container-stack-for-local-development)
* [Prerequisites](#prerequisites)
* [Required External Dependency](#required-external-dependency)
* [Specifying Environment Variables](#specifying-environment-variables)
* [Running the Required Containers](#running-the-required-containers)
* [Running the Compose Stack](#running-the-compose-stack)
Expand All @@ -23,7 +24,7 @@
* [JDK 25 Compact Object Headers](#jdk-25-compact-object-headers)
* [Share the `.m2` Folder to WSL2 Ubuntu](#share-the-m2-folder-to-wsl2-ubuntu)
* [Create a "Link" from WSL2 Ubuntu to Windows's `.m2` Folder](#create-a-link-from-wsl2-ubuntu-to-windowss-m2-folder)
* [Unlink:](#unlink)
* [Unlink](#unlink)
<!-- TOC -->

## Running the Container Stack for Local Development
Expand All @@ -33,6 +34,26 @@
* JDK 25+ (for coding and debugging, but not necessary if running the service in containers)
* Docker Desktop

### Required External Dependency

The project makes use of external dependency [spring-base-commons](https://github.com/vulinh64/spring-base-commons).

* For Windows, run [this script](/create-data-classes.cmd)

* For Linux, run [this script](/create-data-classes.sh)

* Run `chmod +x ./create-data-classes.sh` if you do not have the permission to run the SH file.

Check if your `pom.xml` contains those lines in the `<dependencies>` section:

```xml
<dependency>
<groupId>com.vulinh</groupId>
<artifactId>spring-base-commons</artifactId>
<version>1.0.0</version>
</dependency>
```

### Specifying Environment Variables

The `SPRING_PROFILES_ACTIVE` variable is optional, but you can set it to `development` for local development.
Expand All @@ -45,9 +66,13 @@ An example `.env` file can be copied from [this file](/.env-example).

You can run [this script (Windows only)](/initialize-postgres-keycloak-rabbitmq.cmd) or [this script (Linux only)](/initialize-postgres-keycloak-rabbitmq.sh), and it will start the required containers for local development: PostgreSQL and KeyCloak.

> Both scripts have already handled the external dependency for you. See the [Required External Dependency](#required-external-dependency) section for more info.

## Running the Compose Stack

You can run [this script(Windows only)](/run-docker-compose-stack.cmd) and it will build the service image and start the containers for you.
You can run [this script(Windows only)](/run-docker-compose-stack.cmd), and it will build the service image and start the containers for you.

> Again, both scripts have already handled the external dependency for you.

# Additional Notes

Expand All @@ -59,7 +84,7 @@ platform threads managed by some sort of reactor library.
> [!WARNING]
>
> Test your application thoroughly, as the usage of virtual threads might (theoretically) break critical functions in
your app. Use virtual threads with caution for older projects.
> your app. Use virtual threads with caution for older projects.

### Spring Boot 3.2+

Expand Down Expand Up @@ -191,9 +216,9 @@ rm -rf ~/.m2
ln -s /mnt/c/Users/[your Windows user name]/.m2 ~/.m2
```

Replace `[your Windows user name]` with your actual Windows user name.
Replace `[your Windows user name]` with your actual Windows username.

### Unlink:
### Unlink

```shell
rm -f ~/.m2
Expand Down
10 changes: 10 additions & 0 deletions create-data-classes.cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@echo off

IF EXIST .\build\spring-base-commons rmdir /s /q .\build\spring-base-commons

:: Shallowly clone the repository
git clone --depth 1 https://github.com/vulinh64/spring-base-commons.git .\build\spring-base-commons

rmdir /s /q .\build\spring-base-commons\.git

call .\build\spring-base-commons\mvnw.cmd clean install -f .\build\spring-base-commons\pom.xml
16 changes: 16 additions & 0 deletions create-data-classes.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env sh

set -e

if [ -d "./build/spring-base-commons" ]; then
rm -rf ./build/spring-base-commons
fi

# Shallowly clone the repository
git clone --depth 1 https://github.com/vulinh64/spring-base-commons.git ./build/spring-base-commons

rm -rf ./build/spring-base-commons/.git

chmod +x ./build/spring-base-commons/mvnw

./build/spring-base-commons/mvnw clean install -f ./build/spring-base-commons/pom.xml
77 changes: 77 additions & 0 deletions create-keycloak-data.cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
@echo off
SETLOCAL EnableDelayedExpansion

SET KEYCLOAK_CONTAINER=keycloak
SET KCADM_PATH=/opt/keycloak/bin/kcadm.sh
SET KEYCLOAK_REALM=spring-base
SET CLIENT_NAME=spring-base-client
SET KEYCLOAK_OVERLORD=admin
SET KEYCLOAK_ADMIN_PASSWORD=123456

echo Configuring KCADM credentials...
docker exec %KEYCLOAK_CONTAINER% %KCADM_PATH% config credentials --server http://localhost:8080 --realm master --user %KEYCLOAK_OVERLORD% --password %KEYCLOAK_ADMIN_PASSWORD%
if errorlevel 1 (
echo Error: Failed to configure KCADM credentials
exit /b 1
)

echo Creating realm [%KEYCLOAK_REALM%]...
docker exec %KEYCLOAK_CONTAINER% %KCADM_PATH% create realms -s realm=%KEYCLOAK_REALM% -s enabled=true
if errorlevel 1 (
echo Warning: Realm may already exist, continuing...
)

echo Creating client [%CLIENT_NAME%]...
set "CLIENT_CREATE_CMD=docker exec %KEYCLOAK_CONTAINER% %KCADM_PATH% create clients -r %KEYCLOAK_REALM% -s clientId=%CLIENT_NAME% -s enabled=true -s publicClient=true -s directAccessGrantsEnabled=true -i"
for /f "usebackq delims=" %%i in (`!CLIENT_CREATE_CMD!`) do (
set CLIENT_UUID=%%i
)

if "!CLIENT_UUID!"=="" (
echo Error: Failed to create client or retrieve client UUID
exit /b 1
)

echo Client UUID: !CLIENT_UUID!

REM --- Role Setup ---
SET ROLE_ADMIN=ADMIN
SET ROLE_POWER_USER=POWER_USER
SET ROLE_USER=USER

echo Creating client roles...
docker exec %KEYCLOAK_CONTAINER% %KCADM_PATH% create clients/!CLIENT_UUID!/roles -r %KEYCLOAK_REALM% -s name=%ROLE_ADMIN%
docker exec %KEYCLOAK_CONTAINER% %KCADM_PATH% create clients/!CLIENT_UUID!/roles -r %KEYCLOAK_REALM% -s name=%ROLE_POWER_USER%
docker exec %KEYCLOAK_CONTAINER% %KCADM_PATH% create clients/!CLIENT_UUID!/roles -r %KEYCLOAK_REALM% -s name=%ROLE_USER%

REM --- User Setup ---
set ADMIN_USERNAME=administrator
set POWER_USER_USERNAME=power_user
set USER_USERNAME=user
set DEFAULT_PASSWORD=123456

echo Creating admin user [%ADMIN_USERNAME%]...
docker exec %KEYCLOAK_CONTAINER% %KCADM_PATH% create users -r %KEYCLOAK_REALM% -s username=%ADMIN_USERNAME% -s enabled=true -s email=administrator@email.com -s firstName=Administrator -s lastName=User
docker exec %KEYCLOAK_CONTAINER% %KCADM_PATH% set-password -r %KEYCLOAK_REALM% --username %ADMIN_USERNAME% --new-password %DEFAULT_PASSWORD%

echo Assigning client role [%ROLE_ADMIN%] to user [%ADMIN_USERNAME%]...
docker exec %KEYCLOAK_CONTAINER% %KCADM_PATH% add-roles -r %KEYCLOAK_REALM% --uusername %ADMIN_USERNAME% --cclientid %CLIENT_NAME% --rolename %ROLE_ADMIN%
echo Created user [%ADMIN_USERNAME%] with password %DEFAULT_PASSWORD% and role [%ROLE_ADMIN%]

echo Creating regular user [%USER_USERNAME%]...
docker exec %KEYCLOAK_CONTAINER% %KCADM_PATH% create users -r %KEYCLOAK_REALM% -s username=%USER_USERNAME% -s enabled=true -s email=user@email.com -s firstName=Normal -s lastName=User
docker exec %KEYCLOAK_CONTAINER% %KCADM_PATH% set-password -r %KEYCLOAK_REALM% --username %USER_USERNAME% --new-password %DEFAULT_PASSWORD%

echo Assigning client role [%ROLE_USER%] to user [%USER_USERNAME%]...
docker exec %KEYCLOAK_CONTAINER% %KCADM_PATH% add-roles -r %KEYCLOAK_REALM% --uusername %USER_USERNAME% --cclientid %CLIENT_NAME% --rolename %ROLE_USER%
echo Created user [%USER_USERNAME%] with password %DEFAULT_PASSWORD% and role [%ROLE_USER%]

echo Creating power user [%POWER_USER_USERNAME%]...
docker exec %KEYCLOAK_CONTAINER% %KCADM_PATH% create users -r %KEYCLOAK_REALM% -s username=%POWER_USER_USERNAME% -s enabled=true -s email=power_user@email.com -s firstName=Power -s lastName=User
docker exec %KEYCLOAK_CONTAINER% %KCADM_PATH% set-password -r %KEYCLOAK_REALM% --username %POWER_USER_USERNAME% --new-password %DEFAULT_PASSWORD%

echo Assigning client role [%ROLE_POWER_USER%] to user [%POWER_USER_USERNAME%]...
docker exec %KEYCLOAK_CONTAINER% %KCADM_PATH% add-roles -r %KEYCLOAK_REALM% --uusername %POWER_USER_USERNAME% --cclientid %CLIENT_NAME% --rolename %ROLE_POWER_USER%
echo Created user [%POWER_USER_USERNAME%] with password %DEFAULT_PASSWORD% and role [%ROLE_POWER_USER%]

ENDLOCAL
54 changes: 54 additions & 0 deletions create-keycloak-data.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/usr/bin/env sh

KCADM_PATH="/opt/keycloak/bin/kcadm.sh"
KEYCLOAK_CONTAINER=keycloak
KEYCLOAK_REALM=spring-base
KEYCLOAK_OVERLORD=admin
KEYCLOAK_ADMIN_PASSWORD=123456

echo "Configuring KCADM credentials..."
docker exec "${KEYCLOAK_CONTAINER}" "${KCADM_PATH}" config credentials --server http://localhost:8080 --realm master --user "${KEYCLOAK_OVERLORD}" --password "${KEYCLOAK_ADMIN_PASSWORD}"

docker exec "${KEYCLOAK_CONTAINER}" "${KCADM_PATH}" create realms -s realm="${KEYCLOAK_REALM}" -s enabled=true

CLIENT_NAME=spring-base-client

echo "Creating client [${CLIENT_NAME}]..."

CLIENT_UUID=$(docker exec "${KEYCLOAK_CONTAINER}" "${KCADM_PATH}" create clients -r "${KEYCLOAK_REALM}" -s clientId="${CLIENT_NAME}" -s enabled=true -s publicClient=true -s directAccessGrantsEnabled=true -i)

# --- Role and User Setup ---
ROLE_ADMIN="ADMIN"
ROLE_POWER_USER="POWER_USER"
ROLE_USER="USER"
ADMIN_USERNAME="administrator"
POWER_USER_USERNAME="power_user"
USER_USERNAME="user"

docker exec "${KEYCLOAK_CONTAINER}" "${KCADM_PATH}" create clients/"${CLIENT_UUID}"/roles -r "${KEYCLOAK_REALM}" -s name="${ROLE_ADMIN}"
docker exec "${KEYCLOAK_CONTAINER}" "${KCADM_PATH}" create clients/"${CLIENT_UUID}"/roles -r "${KEYCLOAK_REALM}" -s name="${ROLE_POWER_USER}"
docker exec "${KEYCLOAK_CONTAINER}" "${KCADM_PATH}" create clients/"${CLIENT_UUID}"/roles -r "${KEYCLOAK_REALM}" -s name="${ROLE_USER}"

echo "Creating admin user [${ADMIN_USERNAME}]..."
docker exec "${KEYCLOAK_CONTAINER}" "${KCADM_PATH}" create users -r "${KEYCLOAK_REALM}" -s username="${ADMIN_USERNAME}" -s enabled=true -s email=administrator@email.com -s firstName=Administrator -s lastName=User
docker exec "${KEYCLOAK_CONTAINER}" "${KCADM_PATH}" set-password -r "${KEYCLOAK_REALM}" --username "${ADMIN_USERNAME}" --new-password 123456

echo "Assigning client role [${ROLE_ADMIN}] to user [${ADMIN_USERNAME}] in client [${CLIENT_NAME}]..."
docker exec "${KEYCLOAK_CONTAINER}" "${KCADM_PATH}" add-roles -r "${KEYCLOAK_REALM}" --uusername "${ADMIN_USERNAME}" --cclientid "${CLIENT_NAME}" --rolename "${ROLE_ADMIN}"
echo "Created user [${ADMIN_USERNAME}] with password 123456 and client role [${ROLE_ADMIN}] in client [${CLIENT_NAME}]"

echo "Creating regular user [${USER_USERNAME}]..."
docker exec "${KEYCLOAK_CONTAINER}" "${KCADM_PATH}" create users -r "${KEYCLOAK_REALM}" -s username="${USER_USERNAME}" -s enabled=true -s email=user@email.com -s firstName=Normal -s lastName=User
docker exec "${KEYCLOAK_CONTAINER}" "${KCADM_PATH}" set-password -r "${KEYCLOAK_REALM}" --username "${USER_USERNAME}" --new-password 123456

echo "Assigning client role [${ROLE_USER}] to user [${USER_USERNAME}] in client [${CLIENT_NAME}]..."
docker exec "${KEYCLOAK_CONTAINER}" "${KCADM_PATH}" add-roles -r "${KEYCLOAK_REALM}" --uusername "${USER_USERNAME}" --cclientid "${CLIENT_NAME}" --rolename "${ROLE_USER}"
echo "Created user [${USER_USERNAME}] with password 123456 and client role [${ROLE_USER}] in client [${CLIENT_NAME}]"

echo "Creating power user [${POWER_USER_USERNAME}]..."
docker exec "${KEYCLOAK_CONTAINER}" "${KCADM_PATH}" create users -r "${KEYCLOAK_REALM}" -s username="${POWER_USER_USERNAME}" -s enabled=true -s email=power_user@email.com -s firstName=Power -s lastName=User
docker exec "${KEYCLOAK_CONTAINER}" "${KCADM_PATH}" set-password -r "${KEYCLOAK_REALM}" --username "${POWER_USER_USERNAME}" --new-password 123456

echo "Assigning client role [${ROLE_POWER_USER}] to user [${POWER_USER_USERNAME}] in client [${CLIENT_NAME}]..."
docker exec "${KEYCLOAK_CONTAINER}" "${KCADM_PATH}" add-roles -r "${KEYCLOAK_REALM}" --uusername "${POWER_USER_USERNAME}" --cclientid "${CLIENT_NAME}" --rolename "${ROLE_POWER_USER}"
echo "Created user [${POWER_USER_USERNAME}] with password 123456 and client role [${ROLE_POWER_USER}] in client [${CLIENT_NAME}]"
Loading