This is an automated email from the ASF dual-hosted git repository.

acosentino pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new 85baf356f659 CAMEL-22674 - Camel-Keycloak: Support Bulk Operations 
(#19851)
85baf356f659 is described below

commit 85baf356f6591a9c5200d11b18cbdfc26dad2457
Author: Andrea Cosentino <[email protected]>
AuthorDate: Fri Nov 7 20:14:12 2025 +0100

    CAMEL-22674 - Camel-Keycloak: Support Bulk Operations (#19851)
    
    Signed-off-by: Andrea Cosentino <[email protected]>
---
 .../apache/camel/catalog/components/keycloak.json  |  14 +-
 .../apache/camel/component/keycloak/keycloak.json  |  14 +-
 .../src/main/docs/keycloak-component.adoc          | 556 +++++++++++++++++++++
 .../component/keycloak/KeycloakConstants.java      |  20 +
 .../component/keycloak/KeycloakOperations.java     |   8 +-
 .../camel/component/keycloak/KeycloakProducer.java | 340 +++++++++++++
 .../dsl/KeycloakEndpointBuilderFactory.java        |  74 +++
 7 files changed, 1017 insertions(+), 9 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/keycloak.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/keycloak.json
index f625f191741a..78b35662c72f 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/keycloak.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/keycloak.json
@@ -43,7 +43,7 @@
     "ipAddress": { "index": 16, "kind": "property", "displayName": "Ip 
Address", "group": "common", "label": "", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.keycloak.KeycloakConfiguration", 
"configurationField": "configuration", "description": "Filter events by IP 
address" },
     "keycloakClient": { "index": 17, "kind": "property", "displayName": 
"Keycloak Client", "group": "common", "label": "", "required": false, "type": 
"object", "javaType": "org.keycloak.admin.client.Keycloak", "deprecated": 
false, "deprecationNote": "", "autowired": true, "secret": false, 
"configurationClass": 
"org.apache.camel.component.keycloak.KeycloakConfiguration", 
"configurationField": "configuration", "description": "To use an existing 
configured Keycloak admin client" },
     "maxResults": { "index": 18, "kind": "property", "displayName": "Max 
Results", "group": "common", "label": "", "required": false, "type": "integer", 
"javaType": "int", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": 100, "configurationClass": 
"org.apache.camel.component.keycloak.KeycloakConfiguration", 
"configurationField": "configuration", "description": "Maximum number of events 
to retrieve per poll" },
-    "operation": { "index": 19, "kind": "property", "displayName": 
"Operation", "group": "common", "label": "", "required": false, "type": "enum", 
"javaType": "org.apache.camel.component.keycloak.KeycloakOperations", "enum": [ 
"createRealm", "deleteRealm", "getRealm", "updateRealm", "createUser", 
"deleteUser", "getUser", "updateUser", "listUsers", "searchUsers", 
"createRole", "deleteRole", "getRole", "updateRole", "listRoles", 
"assignRoleToUser", "removeRoleFromUser", "getUserRoles", "cr [...]
+    "operation": { "index": 19, "kind": "property", "displayName": 
"Operation", "group": "common", "label": "", "required": false, "type": "enum", 
"javaType": "org.apache.camel.component.keycloak.KeycloakOperations", "enum": [ 
"createRealm", "deleteRealm", "getRealm", "updateRealm", "createUser", 
"deleteUser", "getUser", "updateUser", "listUsers", "searchUsers", 
"createRole", "deleteRole", "getRole", "updateRole", "listRoles", 
"assignRoleToUser", "removeRoleFromUser", "getUserRoles", "cr [...]
     "operationTypes": { "index": 20, "kind": "property", "displayName": 
"Operation Types", "group": "common", "label": "", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": false, "configurationClass": 
"org.apache.camel.component.keycloak.KeycloakConfiguration", 
"configurationField": "configuration", "description": "Filter admin events by 
operation types (comma-separated list, e.g., CREATE,UPDATE,DELETE)" },
     "password": { "index": 21, "kind": "property", "displayName": "Password", 
"group": "common", "label": "", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": true, "configurationClass": 
"org.apache.camel.component.keycloak.KeycloakConfiguration", 
"configurationField": "configuration", "description": "Keycloak password" },
     "pojoRequest": { "index": 22, "kind": "property", "displayName": "Pojo 
Request", "group": "common", "label": "", "required": false, "type": "boolean", 
"javaType": "boolean", "deprecated": false, "autowired": false, "secret": 
false, "defaultValue": false, "configurationClass": 
"org.apache.camel.component.keycloak.KeycloakConfiguration", 
"configurationField": "configuration", "description": "If we want to use a POJO 
request as body or not" },
@@ -59,7 +59,7 @@
     "autowiredEnabled": { "index": 32, "kind": "property", "displayName": 
"Autowired Enabled", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": true, "description": 
"Whether autowiring is enabled. This is used for automatic autowiring options 
(the option must be marked as autowired) by looking up in the registry to find 
if there is a single instance of matching  [...]
   },
   "headers": {
-    "CamelKeycloakOperation": { "index": 0, "kind": "header", "displayName": 
"", "group": "common", "label": "", "required": false, "javaType": 
"org.apache.camel.component.keycloak.KeycloakOperations", "enum": [ 
"createRealm", "deleteRealm", "getRealm", "updateRealm", "createUser", 
"deleteUser", "getUser", "updateUser", "listUsers", "searchUsers", 
"createRole", "deleteRole", "getRole", "updateRole", "listRoles", 
"assignRoleToUser", "removeRoleFromUser", "getUserRoles", "createGroup", "de 
[...]
+    "CamelKeycloakOperation": { "index": 0, "kind": "header", "displayName": 
"", "group": "common", "label": "", "required": false, "javaType": 
"org.apache.camel.component.keycloak.KeycloakOperations", "enum": [ 
"createRealm", "deleteRealm", "getRealm", "updateRealm", "createUser", 
"deleteUser", "getUser", "updateUser", "listUsers", "searchUsers", 
"createRole", "deleteRole", "getRole", "updateRole", "listRoles", 
"assignRoleToUser", "removeRoleFromUser", "getUserRoles", "createGroup", "de 
[...]
     "CamelKeycloakRealmName": { "index": 1, "kind": "header", "displayName": 
"", "group": "common", "label": "", "required": false, "javaType": "String", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The realm name", "constantName": 
"org.apache.camel.component.keycloak.KeycloakConstants#REALM_NAME" },
     "CamelKeycloakUserId": { "index": 2, "kind": "header", "displayName": "", 
"group": "common", "label": "", "required": false, "javaType": "String", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The user ID", "constantName": 
"org.apache.camel.component.keycloak.KeycloakConstants#USER_ID" },
     "CamelKeycloakUsername": { "index": 3, "kind": "header", "displayName": 
"", "group": "common", "label": "", "required": false, "javaType": "String", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The username", "constantName": 
"org.apache.camel.component.keycloak.KeycloakConstants#USERNAME" },
@@ -101,7 +101,13 @@
     "CamelKeycloakRequiredAction": { "index": 39, "kind": "header", 
"displayName": "", "group": "common", "label": "", "required": false, 
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The required action type", 
"constantName": 
"org.apache.camel.component.keycloak.KeycloakConstants#REQUIRED_ACTION" },
     "CamelKeycloakActions": { "index": 40, "kind": "header", "displayName": 
"", "group": "common", "label": "", "required": false, "javaType": 
"java.util.List<String>", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The list of actions to 
execute", "constantName": 
"org.apache.camel.component.keycloak.KeycloakConstants#ACTIONS" },
     "CamelKeycloakRedirectUri": { "index": 41, "kind": "header", 
"displayName": "", "group": "common", "label": "", "required": false, 
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The redirect URI", "constantName": 
"org.apache.camel.component.keycloak.KeycloakConstants#REDIRECT_URI" },
-    "CamelKeycloakLifespan": { "index": 42, "kind": "header", "displayName": 
"", "group": "common", "label": "", "required": false, "javaType": "Integer", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The lifespan in seconds", "constantName": 
"org.apache.camel.component.keycloak.KeycloakConstants#LIFESPAN" }
+    "CamelKeycloakLifespan": { "index": 42, "kind": "header", "displayName": 
"", "group": "common", "label": "", "required": false, "javaType": "Integer", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The lifespan in seconds", "constantName": 
"org.apache.camel.component.keycloak.KeycloakConstants#LIFESPAN" },
+    "CamelKeycloakUsers": { "index": 43, "kind": "header", "displayName": "", 
"group": "common", "label": "", "required": false, "javaType": 
"java.util.List<org.keycloak.representations.idm.UserRepresentation>", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The list of users for bulk operations", "constantName": 
"org.apache.camel.component.keycloak.KeycloakConstants#USERS" },
+    "CamelKeycloakUserIds": { "index": 44, "kind": "header", "displayName": 
"", "group": "common", "label": "", "required": false, "javaType": 
"java.util.List<String>", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The list of user IDs for 
bulk operations", "constantName": 
"org.apache.camel.component.keycloak.KeycloakConstants#USER_IDS" },
+    "CamelKeycloakUsernames": { "index": 45, "kind": "header", "displayName": 
"", "group": "common", "label": "", "required": false, "javaType": 
"java.util.List<String>", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The list of usernames for 
bulk operations", "constantName": 
"org.apache.camel.component.keycloak.KeycloakConstants#USERNAMES" },
+    "CamelKeycloakRoleNames": { "index": 46, "kind": "header", "displayName": 
"", "group": "common", "label": "", "required": false, "javaType": 
"java.util.List<String>", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The list of role names for 
bulk operations", "constantName": 
"org.apache.camel.component.keycloak.KeycloakConstants#ROLE_NAMES" },
+    "CamelKeycloakContinueOnError": { "index": 47, "kind": "header", 
"displayName": "", "group": "common", "label": "", "required": false, 
"javaType": "Boolean", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "Continue on error during bulk 
operations", "constantName": 
"org.apache.camel.component.keycloak.KeycloakConstants#CONTINUE_ON_ERROR" },
+    "CamelKeycloakBatchSize": { "index": 48, "kind": "header", "displayName": 
"", "group": "common", "label": "", "required": false, "javaType": "Integer", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "Batch size for bulk operations", "constantName": 
"org.apache.camel.component.keycloak.KeycloakConstants#BATCH_SIZE" }
   },
   "properties": {
     "label": { "index": 0, "kind": "path", "displayName": "Label", "group": 
"common", "label": "", "required": true, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "configurationClass": 
"org.apache.camel.component.keycloak.KeycloakConfiguration", 
"configurationField": "configuration", "description": "Logical name" },
@@ -123,7 +129,7 @@
     "ipAddress": { "index": 16, "kind": "parameter", "displayName": "Ip 
Address", "group": "common", "label": "", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.keycloak.KeycloakConfiguration", 
"configurationField": "configuration", "description": "Filter events by IP 
address" },
     "keycloakClient": { "index": 17, "kind": "parameter", "displayName": 
"Keycloak Client", "group": "common", "label": "", "required": false, "type": 
"object", "javaType": "org.keycloak.admin.client.Keycloak", "deprecated": 
false, "deprecationNote": "", "autowired": true, "secret": false, 
"configurationClass": 
"org.apache.camel.component.keycloak.KeycloakConfiguration", 
"configurationField": "configuration", "description": "To use an existing 
configured Keycloak admin client" },
     "maxResults": { "index": 18, "kind": "parameter", "displayName": "Max 
Results", "group": "common", "label": "", "required": false, "type": "integer", 
"javaType": "int", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": 100, "configurationClass": 
"org.apache.camel.component.keycloak.KeycloakConfiguration", 
"configurationField": "configuration", "description": "Maximum number of events 
to retrieve per poll" },
-    "operation": { "index": 19, "kind": "parameter", "displayName": 
"Operation", "group": "common", "label": "", "required": false, "type": "enum", 
"javaType": "org.apache.camel.component.keycloak.KeycloakOperations", "enum": [ 
"createRealm", "deleteRealm", "getRealm", "updateRealm", "createUser", 
"deleteUser", "getUser", "updateUser", "listUsers", "searchUsers", 
"createRole", "deleteRole", "getRole", "updateRole", "listRoles", 
"assignRoleToUser", "removeRoleFromUser", "getUserRoles", "c [...]
+    "operation": { "index": 19, "kind": "parameter", "displayName": 
"Operation", "group": "common", "label": "", "required": false, "type": "enum", 
"javaType": "org.apache.camel.component.keycloak.KeycloakOperations", "enum": [ 
"createRealm", "deleteRealm", "getRealm", "updateRealm", "createUser", 
"deleteUser", "getUser", "updateUser", "listUsers", "searchUsers", 
"createRole", "deleteRole", "getRole", "updateRole", "listRoles", 
"assignRoleToUser", "removeRoleFromUser", "getUserRoles", "c [...]
     "operationTypes": { "index": 20, "kind": "parameter", "displayName": 
"Operation Types", "group": "common", "label": "", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": false, "configurationClass": 
"org.apache.camel.component.keycloak.KeycloakConfiguration", 
"configurationField": "configuration", "description": "Filter admin events by 
operation types (comma-separated list, e.g., CREATE,UPDATE,DELETE)" },
     "password": { "index": 21, "kind": "parameter", "displayName": "Password", 
"group": "common", "label": "", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": true, "configurationClass": 
"org.apache.camel.component.keycloak.KeycloakConfiguration", 
"configurationField": "configuration", "description": "Keycloak password" },
     "pojoRequest": { "index": 22, "kind": "parameter", "displayName": "Pojo 
Request", "group": "common", "label": "", "required": false, "type": "boolean", 
"javaType": "boolean", "deprecated": false, "autowired": false, "secret": 
false, "defaultValue": false, "configurationClass": 
"org.apache.camel.component.keycloak.KeycloakConfiguration", 
"configurationField": "configuration", "description": "If we want to use a POJO 
request as body or not" },
diff --git 
a/components/camel-keycloak/src/generated/resources/META-INF/org/apache/camel/component/keycloak/keycloak.json
 
b/components/camel-keycloak/src/generated/resources/META-INF/org/apache/camel/component/keycloak/keycloak.json
index f625f191741a..78b35662c72f 100644
--- 
a/components/camel-keycloak/src/generated/resources/META-INF/org/apache/camel/component/keycloak/keycloak.json
+++ 
b/components/camel-keycloak/src/generated/resources/META-INF/org/apache/camel/component/keycloak/keycloak.json
@@ -43,7 +43,7 @@
     "ipAddress": { "index": 16, "kind": "property", "displayName": "Ip 
Address", "group": "common", "label": "", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.keycloak.KeycloakConfiguration", 
"configurationField": "configuration", "description": "Filter events by IP 
address" },
     "keycloakClient": { "index": 17, "kind": "property", "displayName": 
"Keycloak Client", "group": "common", "label": "", "required": false, "type": 
"object", "javaType": "org.keycloak.admin.client.Keycloak", "deprecated": 
false, "deprecationNote": "", "autowired": true, "secret": false, 
"configurationClass": 
"org.apache.camel.component.keycloak.KeycloakConfiguration", 
"configurationField": "configuration", "description": "To use an existing 
configured Keycloak admin client" },
     "maxResults": { "index": 18, "kind": "property", "displayName": "Max 
Results", "group": "common", "label": "", "required": false, "type": "integer", 
"javaType": "int", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": 100, "configurationClass": 
"org.apache.camel.component.keycloak.KeycloakConfiguration", 
"configurationField": "configuration", "description": "Maximum number of events 
to retrieve per poll" },
-    "operation": { "index": 19, "kind": "property", "displayName": 
"Operation", "group": "common", "label": "", "required": false, "type": "enum", 
"javaType": "org.apache.camel.component.keycloak.KeycloakOperations", "enum": [ 
"createRealm", "deleteRealm", "getRealm", "updateRealm", "createUser", 
"deleteUser", "getUser", "updateUser", "listUsers", "searchUsers", 
"createRole", "deleteRole", "getRole", "updateRole", "listRoles", 
"assignRoleToUser", "removeRoleFromUser", "getUserRoles", "cr [...]
+    "operation": { "index": 19, "kind": "property", "displayName": 
"Operation", "group": "common", "label": "", "required": false, "type": "enum", 
"javaType": "org.apache.camel.component.keycloak.KeycloakOperations", "enum": [ 
"createRealm", "deleteRealm", "getRealm", "updateRealm", "createUser", 
"deleteUser", "getUser", "updateUser", "listUsers", "searchUsers", 
"createRole", "deleteRole", "getRole", "updateRole", "listRoles", 
"assignRoleToUser", "removeRoleFromUser", "getUserRoles", "cr [...]
     "operationTypes": { "index": 20, "kind": "property", "displayName": 
"Operation Types", "group": "common", "label": "", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": false, "configurationClass": 
"org.apache.camel.component.keycloak.KeycloakConfiguration", 
"configurationField": "configuration", "description": "Filter admin events by 
operation types (comma-separated list, e.g., CREATE,UPDATE,DELETE)" },
     "password": { "index": 21, "kind": "property", "displayName": "Password", 
"group": "common", "label": "", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": true, "configurationClass": 
"org.apache.camel.component.keycloak.KeycloakConfiguration", 
"configurationField": "configuration", "description": "Keycloak password" },
     "pojoRequest": { "index": 22, "kind": "property", "displayName": "Pojo 
Request", "group": "common", "label": "", "required": false, "type": "boolean", 
"javaType": "boolean", "deprecated": false, "autowired": false, "secret": 
false, "defaultValue": false, "configurationClass": 
"org.apache.camel.component.keycloak.KeycloakConfiguration", 
"configurationField": "configuration", "description": "If we want to use a POJO 
request as body or not" },
@@ -59,7 +59,7 @@
     "autowiredEnabled": { "index": 32, "kind": "property", "displayName": 
"Autowired Enabled", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": true, "description": 
"Whether autowiring is enabled. This is used for automatic autowiring options 
(the option must be marked as autowired) by looking up in the registry to find 
if there is a single instance of matching  [...]
   },
   "headers": {
-    "CamelKeycloakOperation": { "index": 0, "kind": "header", "displayName": 
"", "group": "common", "label": "", "required": false, "javaType": 
"org.apache.camel.component.keycloak.KeycloakOperations", "enum": [ 
"createRealm", "deleteRealm", "getRealm", "updateRealm", "createUser", 
"deleteUser", "getUser", "updateUser", "listUsers", "searchUsers", 
"createRole", "deleteRole", "getRole", "updateRole", "listRoles", 
"assignRoleToUser", "removeRoleFromUser", "getUserRoles", "createGroup", "de 
[...]
+    "CamelKeycloakOperation": { "index": 0, "kind": "header", "displayName": 
"", "group": "common", "label": "", "required": false, "javaType": 
"org.apache.camel.component.keycloak.KeycloakOperations", "enum": [ 
"createRealm", "deleteRealm", "getRealm", "updateRealm", "createUser", 
"deleteUser", "getUser", "updateUser", "listUsers", "searchUsers", 
"createRole", "deleteRole", "getRole", "updateRole", "listRoles", 
"assignRoleToUser", "removeRoleFromUser", "getUserRoles", "createGroup", "de 
[...]
     "CamelKeycloakRealmName": { "index": 1, "kind": "header", "displayName": 
"", "group": "common", "label": "", "required": false, "javaType": "String", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The realm name", "constantName": 
"org.apache.camel.component.keycloak.KeycloakConstants#REALM_NAME" },
     "CamelKeycloakUserId": { "index": 2, "kind": "header", "displayName": "", 
"group": "common", "label": "", "required": false, "javaType": "String", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The user ID", "constantName": 
"org.apache.camel.component.keycloak.KeycloakConstants#USER_ID" },
     "CamelKeycloakUsername": { "index": 3, "kind": "header", "displayName": 
"", "group": "common", "label": "", "required": false, "javaType": "String", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The username", "constantName": 
"org.apache.camel.component.keycloak.KeycloakConstants#USERNAME" },
@@ -101,7 +101,13 @@
     "CamelKeycloakRequiredAction": { "index": 39, "kind": "header", 
"displayName": "", "group": "common", "label": "", "required": false, 
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The required action type", 
"constantName": 
"org.apache.camel.component.keycloak.KeycloakConstants#REQUIRED_ACTION" },
     "CamelKeycloakActions": { "index": 40, "kind": "header", "displayName": 
"", "group": "common", "label": "", "required": false, "javaType": 
"java.util.List<String>", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The list of actions to 
execute", "constantName": 
"org.apache.camel.component.keycloak.KeycloakConstants#ACTIONS" },
     "CamelKeycloakRedirectUri": { "index": 41, "kind": "header", 
"displayName": "", "group": "common", "label": "", "required": false, 
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The redirect URI", "constantName": 
"org.apache.camel.component.keycloak.KeycloakConstants#REDIRECT_URI" },
-    "CamelKeycloakLifespan": { "index": 42, "kind": "header", "displayName": 
"", "group": "common", "label": "", "required": false, "javaType": "Integer", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The lifespan in seconds", "constantName": 
"org.apache.camel.component.keycloak.KeycloakConstants#LIFESPAN" }
+    "CamelKeycloakLifespan": { "index": 42, "kind": "header", "displayName": 
"", "group": "common", "label": "", "required": false, "javaType": "Integer", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The lifespan in seconds", "constantName": 
"org.apache.camel.component.keycloak.KeycloakConstants#LIFESPAN" },
+    "CamelKeycloakUsers": { "index": 43, "kind": "header", "displayName": "", 
"group": "common", "label": "", "required": false, "javaType": 
"java.util.List<org.keycloak.representations.idm.UserRepresentation>", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The list of users for bulk operations", "constantName": 
"org.apache.camel.component.keycloak.KeycloakConstants#USERS" },
+    "CamelKeycloakUserIds": { "index": 44, "kind": "header", "displayName": 
"", "group": "common", "label": "", "required": false, "javaType": 
"java.util.List<String>", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The list of user IDs for 
bulk operations", "constantName": 
"org.apache.camel.component.keycloak.KeycloakConstants#USER_IDS" },
+    "CamelKeycloakUsernames": { "index": 45, "kind": "header", "displayName": 
"", "group": "common", "label": "", "required": false, "javaType": 
"java.util.List<String>", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The list of usernames for 
bulk operations", "constantName": 
"org.apache.camel.component.keycloak.KeycloakConstants#USERNAMES" },
+    "CamelKeycloakRoleNames": { "index": 46, "kind": "header", "displayName": 
"", "group": "common", "label": "", "required": false, "javaType": 
"java.util.List<String>", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The list of role names for 
bulk operations", "constantName": 
"org.apache.camel.component.keycloak.KeycloakConstants#ROLE_NAMES" },
+    "CamelKeycloakContinueOnError": { "index": 47, "kind": "header", 
"displayName": "", "group": "common", "label": "", "required": false, 
"javaType": "Boolean", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "Continue on error during bulk 
operations", "constantName": 
"org.apache.camel.component.keycloak.KeycloakConstants#CONTINUE_ON_ERROR" },
+    "CamelKeycloakBatchSize": { "index": 48, "kind": "header", "displayName": 
"", "group": "common", "label": "", "required": false, "javaType": "Integer", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "Batch size for bulk operations", "constantName": 
"org.apache.camel.component.keycloak.KeycloakConstants#BATCH_SIZE" }
   },
   "properties": {
     "label": { "index": 0, "kind": "path", "displayName": "Label", "group": 
"common", "label": "", "required": true, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "configurationClass": 
"org.apache.camel.component.keycloak.KeycloakConfiguration", 
"configurationField": "configuration", "description": "Logical name" },
@@ -123,7 +129,7 @@
     "ipAddress": { "index": 16, "kind": "parameter", "displayName": "Ip 
Address", "group": "common", "label": "", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.keycloak.KeycloakConfiguration", 
"configurationField": "configuration", "description": "Filter events by IP 
address" },
     "keycloakClient": { "index": 17, "kind": "parameter", "displayName": 
"Keycloak Client", "group": "common", "label": "", "required": false, "type": 
"object", "javaType": "org.keycloak.admin.client.Keycloak", "deprecated": 
false, "deprecationNote": "", "autowired": true, "secret": false, 
"configurationClass": 
"org.apache.camel.component.keycloak.KeycloakConfiguration", 
"configurationField": "configuration", "description": "To use an existing 
configured Keycloak admin client" },
     "maxResults": { "index": 18, "kind": "parameter", "displayName": "Max 
Results", "group": "common", "label": "", "required": false, "type": "integer", 
"javaType": "int", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": 100, "configurationClass": 
"org.apache.camel.component.keycloak.KeycloakConfiguration", 
"configurationField": "configuration", "description": "Maximum number of events 
to retrieve per poll" },
-    "operation": { "index": 19, "kind": "parameter", "displayName": 
"Operation", "group": "common", "label": "", "required": false, "type": "enum", 
"javaType": "org.apache.camel.component.keycloak.KeycloakOperations", "enum": [ 
"createRealm", "deleteRealm", "getRealm", "updateRealm", "createUser", 
"deleteUser", "getUser", "updateUser", "listUsers", "searchUsers", 
"createRole", "deleteRole", "getRole", "updateRole", "listRoles", 
"assignRoleToUser", "removeRoleFromUser", "getUserRoles", "c [...]
+    "operation": { "index": 19, "kind": "parameter", "displayName": 
"Operation", "group": "common", "label": "", "required": false, "type": "enum", 
"javaType": "org.apache.camel.component.keycloak.KeycloakOperations", "enum": [ 
"createRealm", "deleteRealm", "getRealm", "updateRealm", "createUser", 
"deleteUser", "getUser", "updateUser", "listUsers", "searchUsers", 
"createRole", "deleteRole", "getRole", "updateRole", "listRoles", 
"assignRoleToUser", "removeRoleFromUser", "getUserRoles", "c [...]
     "operationTypes": { "index": 20, "kind": "parameter", "displayName": 
"Operation Types", "group": "common", "label": "", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": false, "configurationClass": 
"org.apache.camel.component.keycloak.KeycloakConfiguration", 
"configurationField": "configuration", "description": "Filter admin events by 
operation types (comma-separated list, e.g., CREATE,UPDATE,DELETE)" },
     "password": { "index": 21, "kind": "parameter", "displayName": "Password", 
"group": "common", "label": "", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": true, "configurationClass": 
"org.apache.camel.component.keycloak.KeycloakConfiguration", 
"configurationField": "configuration", "description": "Keycloak password" },
     "pojoRequest": { "index": 22, "kind": "parameter", "displayName": "Pojo 
Request", "group": "common", "label": "", "required": false, "type": "boolean", 
"javaType": "boolean", "deprecated": false, "autowired": false, "secret": 
false, "defaultValue": false, "configurationClass": 
"org.apache.camel.component.keycloak.KeycloakConfiguration", 
"configurationField": "configuration", "description": "If we want to use a POJO 
request as body or not" },
diff --git a/components/camel-keycloak/src/main/docs/keycloak-component.adoc 
b/components/camel-keycloak/src/main/docs/keycloak-component.adoc
index 90aedb295caa..07fb79288fd4 100644
--- a/components/camel-keycloak/src/main/docs/keycloak-component.adoc
+++ b/components/camel-keycloak/src/main/docs/keycloak-component.adoc
@@ -1396,6 +1396,562 @@ 
template.sendBodyAndHeaders("keycloak:admin?operation=createResourcePermission&p
 
template.sendBodyAndHeaders("keycloak:admin?operation=listResourcePermissions", 
null, permHeaders);
 ----
 
+=== Bulk Operations
+
+Bulk operations allow you to perform multiple operations in a single request, 
improving efficiency and reducing network overhead. These operations are 
particularly useful for provisioning, migrations, and large-scale 
administrative tasks.
+
+==== Bulk Create Users
+
+Create multiple users in a single operation with detailed results for each 
user.
+
+[tabs]
+====
+Java::
++
+[source,java]
+----
+// Create multiple users at once
+List<UserRepresentation> users = new ArrayList<>();
+
+for (int i = 1; i <= 100; i++) {
+    UserRepresentation user = new UserRepresentation();
+    user.setUsername("user" + i);
+    user.setEmail("user" + i + "@company.com");
+    user.setFirstName("User");
+    user.setLastName("" + i);
+    user.setEnabled(true);
+    users.add(user);
+}
+
+Map<String, Object> headers = new HashMap<>();
+headers.put(KeycloakConstants.REALM_NAME, "my-realm");
+headers.put(KeycloakConstants.CONTINUE_ON_ERROR, true); // Continue even if 
some users fail
+
+Map<String, Object> result = template.requestBodyAndHeaders(
+    "keycloak:admin?operation=bulkCreateUsers", users, headers, Map.class);
+
+// Result contains summary and details
+System.out.println("Total: " + result.get("total"));
+System.out.println("Success: " + result.get("success"));
+System.out.println("Failed: " + result.get("failed"));
+
+// Detailed results for each user
+List<Map<String, Object>> results = (List<Map<String, Object>>) 
result.get("results");
+for (Map<String, Object> userResult : results) {
+    System.out.println("User: " + userResult.get("username") + " - " + 
userResult.get("status"));
+}
+----
+
+YAML::
++
+[source,yaml]
+----
+# Bulk create users route
+- route:
+    from:
+      uri: direct:bulk-create-users
+      steps:
+        - setHeader:
+            name: CamelKeycloakRealmName
+            constant: "my-realm"
+        - setHeader:
+            name: CamelKeycloakContinueOnError
+            constant: true
+        - to:
+            uri: keycloak:admin?operation=bulkCreateUsers
+        - log: "Created ${body[success]} out of ${body[total]} users"
+----
+====
+
+==== Bulk Delete Users
+
+Delete multiple users by user IDs or usernames in a single operation.
+
+[tabs]
+====
+Java::
++
+[source,java]
+----
+// Delete by user IDs
+List<String> userIds = List.of("user-id-1", "user-id-2", "user-id-3");
+
+Map<String, Object> headers = new HashMap<>();
+headers.put(KeycloakConstants.REALM_NAME, "my-realm");
+headers.put(KeycloakConstants.USER_IDS, userIds);
+headers.put(KeycloakConstants.CONTINUE_ON_ERROR, true);
+
+Map<String, Object> result = template.requestBodyAndHeaders(
+    "keycloak:admin?operation=bulkDeleteUsers", null, headers, Map.class);
+
+// Or delete by usernames
+List<String> usernames = List.of("user1", "user2", "user3");
+headers.put(KeycloakConstants.USERNAMES, usernames);
+headers.remove(KeycloakConstants.USER_IDS);
+
+result = template.requestBodyAndHeaders(
+    "keycloak:admin?operation=bulkDeleteUsers", null, headers, Map.class);
+
+System.out.println("Deleted " + result.get("success") + " users");
+----
+
+YAML::
++
+[source,yaml]
+----
+# Bulk delete users by usernames
+- route:
+    from:
+      uri: direct:bulk-delete-users
+      steps:
+        - setHeader:
+            name: CamelKeycloakRealmName
+            constant: "my-realm"
+        - setHeader:
+            name: CamelKeycloakUsernames
+            simple: "${body}"  # List of usernames
+        - setHeader:
+            name: CamelKeycloakContinueOnError
+            constant: true
+        - to:
+            uri: keycloak:admin?operation=bulkDeleteUsers
+        - log: "Deleted ${body[success]} out of ${body[total]} users"
+----
+====
+
+==== Bulk Assign Roles to User
+
+Assign multiple roles to a single user in one operation.
+
+[tabs]
+====
+Java::
++
+[source,java]
+----
+// Assign multiple roles to one user
+List<String> roleNames = List.of("admin", "manager", "developer");
+
+Map<String, Object> headers = new HashMap<>();
+headers.put(KeycloakConstants.REALM_NAME, "my-realm");
+headers.put(KeycloakConstants.USER_ID, "user-id-123");
+headers.put(KeycloakConstants.ROLE_NAMES, roleNames);
+headers.put(KeycloakConstants.CONTINUE_ON_ERROR, true);
+
+Map<String, Object> result = template.requestBodyAndHeaders(
+    "keycloak:admin?operation=bulkAssignRolesToUser", null, headers, 
Map.class);
+
+System.out.println("Assigned " + result.get("assigned") + " roles to user");
+
+// Detailed results
+List<Map<String, Object>> results = (List<Map<String, Object>>) 
result.get("results");
+for (Map<String, Object> roleResult : results) {
+    System.out.println("Role: " + roleResult.get("roleName") + " - " + 
roleResult.get("status"));
+}
+----
+
+YAML::
++
+[source,yaml]
+----
+# Assign multiple roles to a user
+- route:
+    from:
+      uri: direct:assign-roles-to-user
+      steps:
+        - setHeader:
+            name: CamelKeycloakRealmName
+            constant: "my-realm"
+        - setHeader:
+            name: CamelKeycloakUserId
+            simple: "${body[userId]}"
+        - setHeader:
+            name: CamelKeycloakRoleNames
+            simple: "${body[roles]}"  # List of role names
+        - setHeader:
+            name: CamelKeycloakContinueOnError
+            constant: true
+        - to:
+            uri: keycloak:admin?operation=bulkAssignRolesToUser
+        - log: "Assigned ${body[assigned]} roles to user"
+----
+====
+
+==== Bulk Assign Role to Users
+
+Assign a single role to multiple users in one operation.
+
+[tabs]
+====
+Java::
++
+[source,java]
+----
+// Assign one role to multiple users
+List<String> userIds = List.of("user-id-1", "user-id-2", "user-id-3");
+
+Map<String, Object> headers = new HashMap<>();
+headers.put(KeycloakConstants.REALM_NAME, "my-realm");
+headers.put(KeycloakConstants.ROLE_NAME, "developer");
+headers.put(KeycloakConstants.USER_IDS, userIds);
+headers.put(KeycloakConstants.CONTINUE_ON_ERROR, true);
+
+Map<String, Object> result = template.requestBodyAndHeaders(
+    "keycloak:admin?operation=bulkAssignRoleToUsers", null, headers, 
Map.class);
+
+System.out.println("Assigned role to " + result.get("success") + " users");
+
+// Or use usernames instead of IDs
+List<String> usernames = List.of("user1", "user2", "user3");
+headers.put(KeycloakConstants.USERNAMES, usernames);
+headers.remove(KeycloakConstants.USER_IDS);
+
+result = template.requestBodyAndHeaders(
+    "keycloak:admin?operation=bulkAssignRoleToUsers", null, headers, 
Map.class);
+----
+
+YAML::
++
+[source,yaml]
+----
+# Assign a role to multiple users
+- route:
+    from:
+      uri: direct:assign-role-to-users
+      steps:
+        - setHeader:
+            name: CamelKeycloakRealmName
+            constant: "my-realm"
+        - setHeader:
+            name: CamelKeycloakRoleName
+            constant: "developer"
+        - setHeader:
+            name: CamelKeycloakUsernames
+            simple: "${body}"  # List of usernames
+        - setHeader:
+            name: CamelKeycloakContinueOnError
+            constant: true
+        - to:
+            uri: keycloak:admin?operation=bulkAssignRoleToUsers
+        - log: "Assigned role to ${body[success]} out of ${body[total]} users"
+----
+====
+
+==== Bulk Update Users
+
+Update multiple users in a single operation.
+
+[tabs]
+====
+Java::
++
+[source,java]
+----
+// Update multiple users
+List<UserRepresentation> users = new ArrayList<>();
+
+// Fetch users and update them
+List<UserRepresentation> existingUsers = template.requestBodyAndHeader(
+    "keycloak:admin?operation=listUsers", null,
+    KeycloakConstants.REALM_NAME, "my-realm", List.class);
+
+for (UserRepresentation user : existingUsers) {
+    // Update user properties
+    user.setFirstName("Updated");
+    user.setEnabled(true);
+    users.add(user);
+}
+
+Map<String, Object> headers = new HashMap<>();
+headers.put(KeycloakConstants.REALM_NAME, "my-realm");
+headers.put(KeycloakConstants.USERS, users);
+headers.put(KeycloakConstants.CONTINUE_ON_ERROR, true);
+
+Map<String, Object> result = template.requestBodyAndHeaders(
+    "keycloak:admin?operation=bulkUpdateUsers", null, headers, Map.class);
+
+System.out.println("Updated " + result.get("success") + " users");
+
+// Detailed results
+List<Map<String, Object>> results = (List<Map<String, Object>>) 
result.get("results");
+for (Map<String, Object> userResult : results) {
+    System.out.println("User: " + userResult.get("username") + " - " + 
userResult.get("status"));
+}
+----
+
+YAML::
++
+[source,yaml]
+----
+# Bulk update users
+- route:
+    from:
+      uri: direct:bulk-update-users
+      steps:
+        - setHeader:
+            name: CamelKeycloakRealmName
+            constant: "my-realm"
+        - setHeader:
+            name: CamelKeycloakContinueOnError
+            constant: true
+        - to:
+            uri: keycloak:admin?operation=bulkUpdateUsers
+        - log: "Updated ${body[success]} out of ${body[total]} users"
+----
+====
+
+==== Bulk Operations Response Format
+
+All bulk operations return a consistent response format with the following 
structure:
+
+[source,json]
+----
+{
+  "total": 10,           // Total number of items processed
+  "success": 8,          // Number of successful operations
+  "failed": 2,           // Number of failed operations
+  "results": [           // Detailed results for each item
+    {
+      "username": "user1",
+      "status": "success",
+      "statusCode": 201
+    },
+    {
+      "username": "user2",
+      "status": "failed",
+      "error": "User already exists"
+    }
+  ]
+}
+----
+
+==== Error Handling in Bulk Operations
+
+Bulk operations support the `CamelKeycloakContinueOnError` header to control 
error handling behavior:
+
+[tabs]
+====
+Java::
++
+[source,java]
+----
+// Continue processing even if some operations fail
+headers.put(KeycloakConstants.CONTINUE_ON_ERROR, true);
+
+// Stop on first error (default behavior)
+headers.put(KeycloakConstants.CONTINUE_ON_ERROR, false);
+----
+
+YAML::
++
+[source,yaml]
+----
+# Continue on error
+- setHeader:
+    name: CamelKeycloakContinueOnError
+    constant: true
+
+# Stop on first error
+- setHeader:
+    name: CamelKeycloakContinueOnError
+    constant: false
+----
+====
+
+==== Complete Bulk Operations Example
+
+[tabs]
+====
+Java::
++
+[source,java]
+----
+public class BulkUserProvisioningRoute extends RouteBuilder {
+    @Override
+    public void configure() throws Exception {
+        // Provision users from CSV file
+        from("file:data/incoming?noop=true")
+            .routeId("bulk-user-provisioning")
+            .log("Processing user provisioning file: ${header.CamelFileName}")
+
+            // Parse CSV to user objects
+            .unmarshal().csv()
+            .process(exchange -> {
+                List<List<String>> csvData = 
exchange.getIn().getBody(List.class);
+                List<UserRepresentation> users = new ArrayList<>();
+
+                // Skip header row
+                for (int i = 1; i < csvData.size(); i++) {
+                    List<String> row = csvData.get(i);
+                    UserRepresentation user = new UserRepresentation();
+                    user.setUsername(row.get(0));
+                    user.setEmail(row.get(1));
+                    user.setFirstName(row.get(2));
+                    user.setLastName(row.get(3));
+                    user.setEnabled(true);
+                    users.add(user);
+                }
+
+                exchange.getIn().setBody(users);
+            })
+
+            // Bulk create users
+            .setHeader(KeycloakConstants.REALM_NAME, constant("my-realm"))
+            .setHeader(KeycloakConstants.CONTINUE_ON_ERROR, constant(true))
+            .to("keycloak:admin?operation=bulkCreateUsers")
+
+            // Log results
+            .process(exchange -> {
+                Map<String, Object> result = 
exchange.getIn().getBody(Map.class);
+                log.info("User provisioning completed: {} succeeded, {} failed 
out of {}",
+                    result.get("success"), result.get("failed"), 
result.get("total"));
+            })
+
+            // Assign default role to all successfully created users
+            .filter(simple("${body[success]} > 0"))
+            .process(exchange -> {
+                // Extract user IDs from results
+                Map<String, Object> createResult = 
exchange.getIn().getBody(Map.class);
+                // Get created users and assign role...
+            });
+
+        // Bulk role assignment from JSON
+        from("rest:post:/users/assign-roles")
+            .routeId("bulk-assign-roles")
+            .log("Bulk assigning roles to users")
+            .unmarshal().json()
+            .setHeader(KeycloakConstants.REALM_NAME, simple("${body[realm]}"))
+            .setHeader(KeycloakConstants.USER_ID, simple("${body[userId]}"))
+            .setBody(simple("${body[roles]}"))
+            .setHeader(KeycloakConstants.CONTINUE_ON_ERROR, constant(true))
+            .to("keycloak:admin?operation=bulkAssignRolesToUser")
+            .marshal().json()
+            .setHeader("Content-Type", constant("application/json"));
+
+        // Cleanup inactive users
+        from("timer:cleanup?period=86400000") // Daily
+            .routeId("cleanup-inactive-users")
+            .log("Starting inactive user cleanup")
+            .setHeader(KeycloakConstants.REALM_NAME, constant("my-realm"))
+            .to("keycloak:admin?operation=listUsers")
+            .process(exchange -> {
+                List<UserRepresentation> allUsers = 
exchange.getIn().getBody(List.class);
+                List<String> inactiveUserIds = new ArrayList<>();
+
+                // Identify inactive users (custom logic)
+                for (UserRepresentation user : allUsers) {
+                    // Check last login, attributes, etc.
+                    if (isInactive(user)) {
+                        inactiveUserIds.add(user.getId());
+                    }
+                }
+
+                exchange.getIn().setBody(inactiveUserIds);
+            })
+            .filter(simple("${body.size} > 0"))
+            .setHeader(KeycloakConstants.CONTINUE_ON_ERROR, constant(true))
+            .to("keycloak:admin?operation=bulkDeleteUsers")
+            .log("Deleted ${body[success]} inactive users");
+    }
+
+    private boolean isInactive(UserRepresentation user) {
+        // Custom logic to determine if user is inactive
+        return false;
+    }
+}
+----
+
+YAML::
++
+[source,yaml]
+----
+# Bulk user provisioning from CSV
+- route:
+    id: bulk-user-provisioning
+    from:
+      uri: file:data/incoming?noop=true
+      steps:
+        - log: "Processing user provisioning file: ${header.CamelFileName}"
+        - unmarshal:
+            csv: {}
+        - process:
+            ref: csvToUsersProcessor
+        - setHeader:
+            name: CamelKeycloakRealmName
+            constant: "my-realm"
+        - setHeader:
+            name: CamelKeycloakContinueOnError
+            constant: true
+        - to:
+            uri: keycloak:admin?operation=bulkCreateUsers
+        - log: "Provisioning completed: ${body[success]} succeeded, 
${body[failed]} failed"
+
+# Bulk role assignment API
+- rest:
+    post:
+      - uri: /users/assign-roles
+        to: direct:bulk-assign-roles
+
+- route:
+    id: bulk-assign-roles
+    from:
+      uri: direct:bulk-assign-roles
+      steps:
+        - unmarshal:
+            json: {}
+        - setHeader:
+            name: CamelKeycloakRealmName
+            simple: "${body[realm]}"
+        - setHeader:
+            name: CamelKeycloakUserId
+            simple: "${body[userId]}"
+        - setBody:
+            simple: "${body[roles]}"
+        - setHeader:
+            name: CamelKeycloakContinueOnError
+            constant: true
+        - to:
+            uri: keycloak:admin?operation=bulkAssignRolesToUser
+        - marshal:
+            json: {}
+
+# Daily cleanup of inactive users
+- route:
+    id: cleanup-inactive-users
+    from:
+      uri: timer:cleanup?period=86400000
+      steps:
+        - log: "Starting inactive user cleanup"
+        - setHeader:
+            name: CamelKeycloakRealmName
+            constant: "my-realm"
+        - to:
+            uri: keycloak:admin?operation=listUsers
+        - process:
+            ref: identifyInactiveUsersProcessor
+        - filter:
+            simple: "${body.size} > 0"
+            steps:
+              - setHeader:
+                  name: CamelKeycloakContinueOnError
+                  constant: true
+              - to:
+                  uri: keycloak:admin?operation=bulkDeleteUsers
+              - log: "Deleted ${body[success]} inactive users"
+----
+====
+
+==== Best Practices for Bulk Operations
+
+1. **Use Continue on Error**: Always set `continueOnError=true` for bulk 
operations to get complete feedback on all items
+2. **Monitor Results**: Check the results map to identify and handle failures 
appropriately
+3. **Batch Size**: For very large datasets, consider splitting into smaller 
batches (e.g., 100-500 users per batch)
+4. **Error Handling**: Implement proper error handling and retry logic for 
failed items
+5. **Logging**: Log detailed results for audit and troubleshooting purposes
+6. **Testing**: Test bulk operations with small datasets first before running 
in production
+7. **Performance**: Bulk operations are more efficient than individual 
operations but still require appropriate timeout settings
+8. **Transactions**: Note that Keycloak operations are not transactional - 
some items may succeed while others fail
+
 === Complete Producer Example
 
 [tabs]
diff --git 
a/components/camel-keycloak/src/main/java/org/apache/camel/component/keycloak/KeycloakConstants.java
 
b/components/camel-keycloak/src/main/java/org/apache/camel/component/keycloak/KeycloakConstants.java
index 8ec28b169dbb..dfd4a2f9c72b 100644
--- 
a/components/camel-keycloak/src/main/java/org/apache/camel/component/keycloak/KeycloakConstants.java
+++ 
b/components/camel-keycloak/src/main/java/org/apache/camel/component/keycloak/KeycloakConstants.java
@@ -154,6 +154,26 @@ public final class KeycloakConstants {
     @Metadata(description = "The lifespan in seconds", javaType = "Integer")
     public static final String LIFESPAN = "CamelKeycloakLifespan";
 
+    // Bulk operations constants
+    @Metadata(description = "The list of users for bulk operations",
+              javaType = 
"java.util.List<org.keycloak.representations.idm.UserRepresentation>")
+    public static final String USERS = "CamelKeycloakUsers";
+
+    @Metadata(description = "The list of user IDs for bulk operations", 
javaType = "java.util.List<String>")
+    public static final String USER_IDS = "CamelKeycloakUserIds";
+
+    @Metadata(description = "The list of usernames for bulk operations", 
javaType = "java.util.List<String>")
+    public static final String USERNAMES = "CamelKeycloakUsernames";
+
+    @Metadata(description = "The list of role names for bulk operations", 
javaType = "java.util.List<String>")
+    public static final String ROLE_NAMES = "CamelKeycloakRoleNames";
+
+    @Metadata(description = "Continue on error during bulk operations", 
javaType = "Boolean")
+    public static final String CONTINUE_ON_ERROR = 
"CamelKeycloakContinueOnError";
+
+    @Metadata(description = "Batch size for bulk operations", javaType = 
"Integer")
+    public static final String BATCH_SIZE = "CamelKeycloakBatchSize";
+
     private KeycloakConstants() {
         // Utility class
     }
diff --git 
a/components/camel-keycloak/src/main/java/org/apache/camel/component/keycloak/KeycloakOperations.java
 
b/components/camel-keycloak/src/main/java/org/apache/camel/component/keycloak/KeycloakOperations.java
index 0499d978b6cf..5743a5a00718 100644
--- 
a/components/camel-keycloak/src/main/java/org/apache/camel/component/keycloak/KeycloakOperations.java
+++ 
b/components/camel-keycloak/src/main/java/org/apache/camel/component/keycloak/KeycloakOperations.java
@@ -108,5 +108,11 @@ public enum KeycloakOperations {
     executeActionsEmail,
     // Client Secret Management
     getClientSecret,
-    regenerateClientSecret
+    regenerateClientSecret,
+    // Bulk operations
+    bulkCreateUsers,
+    bulkDeleteUsers,
+    bulkAssignRolesToUser,
+    bulkAssignRoleToUsers,
+    bulkUpdateUsers
 }
diff --git 
a/components/camel-keycloak/src/main/java/org/apache/camel/component/keycloak/KeycloakProducer.java
 
b/components/camel-keycloak/src/main/java/org/apache/camel/component/keycloak/KeycloakProducer.java
index bd60adb2d749..b5635daa81d3 100644
--- 
a/components/camel-keycloak/src/main/java/org/apache/camel/component/keycloak/KeycloakProducer.java
+++ 
b/components/camel-keycloak/src/main/java/org/apache/camel/component/keycloak/KeycloakProducer.java
@@ -29,6 +29,7 @@ import org.apache.camel.Exchange;
 import org.apache.camel.InvalidPayloadException;
 import org.apache.camel.Message;
 import org.apache.camel.support.DefaultProducer;
+import org.apache.camel.util.CastUtils;
 import org.apache.camel.util.ObjectHelper;
 import org.apache.camel.util.URISupport;
 import org.keycloak.admin.client.Keycloak;
@@ -315,6 +316,21 @@ public class KeycloakProducer extends DefaultProducer {
             case regenerateClientSecret:
                 regenerateClientSecret(getEndpoint().getKeycloakClient(), 
exchange);
                 break;
+            case bulkCreateUsers:
+                bulkCreateUsers(getEndpoint().getKeycloakClient(), exchange);
+                break;
+            case bulkDeleteUsers:
+                bulkDeleteUsers(getEndpoint().getKeycloakClient(), exchange);
+                break;
+            case bulkAssignRolesToUser:
+                bulkAssignRolesToUser(getEndpoint().getKeycloakClient(), 
exchange);
+                break;
+            case bulkAssignRoleToUsers:
+                bulkAssignRoleToUsers(getEndpoint().getKeycloakClient(), 
exchange);
+                break;
+            case bulkUpdateUsers:
+                bulkUpdateUsers(getEndpoint().getKeycloakClient(), exchange);
+                break;
             default:
                 throw new IllegalArgumentException("Unsupported operation: " + 
operation);
         }
@@ -1993,6 +2009,330 @@ public class KeycloakProducer extends DefaultProducer {
         message.setBody(newSecret);
     }
 
+    // Bulk operations
+    private void bulkCreateUsers(Keycloak keycloakClient, Exchange exchange) 
throws InvalidPayloadException {
+        String realmName = 
exchange.getIn().getHeader(KeycloakConstants.REALM_NAME, String.class);
+        if (ObjectHelper.isEmpty(realmName)) {
+            throw new IllegalArgumentException(MISSING_REALM_NAME);
+        }
+
+        List<UserRepresentation> users = 
exchange.getIn().getHeader(KeycloakConstants.USERS, List.class);
+        if (users == null || users.isEmpty()) {
+            // Try to get from body
+            Object payload = exchange.getIn().getMandatoryBody();
+            if (payload instanceof List) {
+                users = CastUtils.cast((List<?>) payload);
+            } else {
+                throw new IllegalArgumentException("Users list must be 
provided via header or body");
+            }
+        }
+
+        boolean continueOnError
+                = 
exchange.getIn().getHeader(KeycloakConstants.CONTINUE_ON_ERROR, Boolean.FALSE, 
Boolean.class);
+        List<Map<String, Object>> results = new ArrayList<>();
+        int successCount = 0;
+        int failureCount = 0;
+
+        for (UserRepresentation user : users) {
+            Map<String, Object> result = new HashMap<>();
+            result.put("username", user.getUsername());
+            try {
+                Response response = 
keycloakClient.realm(realmName).users().create(user);
+                result.put("status", "success");
+                result.put("statusCode", response.getStatus());
+                successCount++;
+                response.close();
+            } catch (Exception e) {
+                result.put("status", "failed");
+                result.put("error", e.getMessage());
+                failureCount++;
+                if (!continueOnError) {
+                    throw new RuntimeException("Failed to create user: " + 
user.getUsername(), e);
+                }
+            }
+            results.add(result);
+        }
+
+        Map<String, Object> summary = new HashMap<>();
+        summary.put("total", users.size());
+        summary.put("success", successCount);
+        summary.put("failed", failureCount);
+        summary.put("results", results);
+
+        Message message = getMessageForResponse(exchange);
+        message.setBody(summary);
+    }
+
+    private void bulkDeleteUsers(Keycloak keycloakClient, Exchange exchange) {
+        String realmName = 
exchange.getIn().getHeader(KeycloakConstants.REALM_NAME, String.class);
+        if (ObjectHelper.isEmpty(realmName)) {
+            throw new IllegalArgumentException(MISSING_REALM_NAME);
+        }
+
+        List<String> userIds = 
exchange.getIn().getHeader(KeycloakConstants.USER_IDS, List.class);
+        if (userIds == null || userIds.isEmpty()) {
+            // Try usernames
+            List<String> usernames = 
exchange.getIn().getHeader(KeycloakConstants.USERNAMES, List.class);
+            if (usernames == null || usernames.isEmpty()) {
+                // Try to get from body
+                Object payload = exchange.getIn().getBody();
+                if (payload instanceof List) {
+                    userIds = CastUtils.cast((List<?>) payload);
+                } else {
+                    throw new IllegalArgumentException("User IDs or usernames 
must be provided via header or body");
+                }
+            } else {
+                // Convert usernames to user IDs
+                userIds = new ArrayList<>();
+                for (String username : usernames) {
+                    List<UserRepresentation> foundUsers
+                            = 
keycloakClient.realm(realmName).users().searchByUsername(username, true);
+                    if (!foundUsers.isEmpty()) {
+                        userIds.add(foundUsers.get(0).getId());
+                    }
+                }
+            }
+        }
+
+        boolean continueOnError
+                = 
exchange.getIn().getHeader(KeycloakConstants.CONTINUE_ON_ERROR, Boolean.FALSE, 
Boolean.class);
+        List<Map<String, Object>> results = new ArrayList<>();
+        int successCount = 0;
+        int failureCount = 0;
+
+        for (String userId : userIds) {
+            Map<String, Object> result = new HashMap<>();
+            result.put("userId", userId);
+            try {
+                Response response = 
keycloakClient.realm(realmName).users().delete(userId);
+                result.put("status", "success");
+                result.put("statusCode", response.getStatus());
+                successCount++;
+                response.close();
+            } catch (Exception e) {
+                result.put("status", "failed");
+                result.put("error", e.getMessage());
+                failureCount++;
+                if (!continueOnError) {
+                    throw new RuntimeException("Failed to delete user: " + 
userId, e);
+                }
+            }
+            results.add(result);
+        }
+
+        Map<String, Object> summary = new HashMap<>();
+        summary.put("total", userIds.size());
+        summary.put("success", successCount);
+        summary.put("failed", failureCount);
+        summary.put("results", results);
+
+        Message message = getMessageForResponse(exchange);
+        message.setBody(summary);
+    }
+
+    private void bulkAssignRolesToUser(Keycloak keycloakClient, Exchange 
exchange) {
+        String realmName = 
exchange.getIn().getHeader(KeycloakConstants.REALM_NAME, String.class);
+        if (ObjectHelper.isEmpty(realmName)) {
+            throw new IllegalArgumentException(MISSING_REALM_NAME);
+        }
+
+        String userId = exchange.getIn().getHeader(KeycloakConstants.USER_ID, 
String.class);
+        if (ObjectHelper.isEmpty(userId)) {
+            throw new IllegalArgumentException(MISSING_USER_ID);
+        }
+
+        List<String> roleNames = 
exchange.getIn().getHeader(KeycloakConstants.ROLE_NAMES, List.class);
+        if (roleNames == null || roleNames.isEmpty()) {
+            // Try to get from body
+            Object payload = exchange.getIn().getBody();
+            if (payload instanceof List) {
+                roleNames = CastUtils.cast((List<?>) payload);
+            } else {
+                throw new IllegalArgumentException("Role names must be 
provided via header or body");
+            }
+        }
+
+        boolean continueOnError
+                = 
exchange.getIn().getHeader(KeycloakConstants.CONTINUE_ON_ERROR, Boolean.FALSE, 
Boolean.class);
+        List<Map<String, Object>> results = new ArrayList<>();
+        List<RoleRepresentation> rolesToAssign = new ArrayList<>();
+        int successCount = 0;
+        int failureCount = 0;
+
+        // Collect all roles first
+        for (String roleName : roleNames) {
+            Map<String, Object> result = new HashMap<>();
+            result.put("roleName", roleName);
+            try {
+                RoleRepresentation role = 
keycloakClient.realm(realmName).roles().get(roleName).toRepresentation();
+                rolesToAssign.add(role);
+                result.put("status", "found");
+                successCount++;
+            } catch (Exception e) {
+                result.put("status", "not_found");
+                result.put("error", e.getMessage());
+                failureCount++;
+                if (!continueOnError) {
+                    throw new RuntimeException("Failed to find role: " + 
roleName, e);
+                }
+            }
+            results.add(result);
+        }
+
+        // Assign all roles at once if any were found
+        if (!rolesToAssign.isEmpty()) {
+            try {
+                
keycloakClient.realm(realmName).users().get(userId).roles().realmLevel().add(rolesToAssign);
+            } catch (Exception e) {
+                throw new RuntimeException("Failed to assign roles to user: " 
+ userId, e);
+            }
+        }
+
+        Map<String, Object> summary = new HashMap<>();
+        summary.put("total", roleNames.size());
+        summary.put("success", successCount);
+        summary.put("failed", failureCount);
+        summary.put("assigned", rolesToAssign.size());
+        summary.put("results", results);
+
+        Message message = getMessageForResponse(exchange);
+        message.setBody(summary);
+    }
+
+    private void bulkAssignRoleToUsers(Keycloak keycloakClient, Exchange 
exchange) {
+        String realmName = 
exchange.getIn().getHeader(KeycloakConstants.REALM_NAME, String.class);
+        if (ObjectHelper.isEmpty(realmName)) {
+            throw new IllegalArgumentException(MISSING_REALM_NAME);
+        }
+
+        String roleName = 
exchange.getIn().getHeader(KeycloakConstants.ROLE_NAME, String.class);
+        if (ObjectHelper.isEmpty(roleName)) {
+            throw new IllegalArgumentException(MISSING_ROLE_NAME);
+        }
+
+        // Get the role first
+        RoleRepresentation role;
+        try {
+            role = 
keycloakClient.realm(realmName).roles().get(roleName).toRepresentation();
+        } catch (Exception e) {
+            throw new RuntimeException("Failed to find role: " + roleName, e);
+        }
+
+        List<String> userIds = 
exchange.getIn().getHeader(KeycloakConstants.USER_IDS, List.class);
+        if (userIds == null || userIds.isEmpty()) {
+            // Try usernames
+            List<String> usernames = 
exchange.getIn().getHeader(KeycloakConstants.USERNAMES, List.class);
+            if (usernames == null || usernames.isEmpty()) {
+                // Try to get from body
+                Object payload = exchange.getIn().getBody();
+                if (payload instanceof List) {
+                    userIds = CastUtils.cast((List<?>) payload);
+                } else {
+                    throw new IllegalArgumentException("User IDs or usernames 
must be provided via header or body");
+                }
+            } else {
+                // Convert usernames to user IDs
+                userIds = new ArrayList<>();
+                for (String username : usernames) {
+                    List<UserRepresentation> foundUsers
+                            = 
keycloakClient.realm(realmName).users().searchByUsername(username, true);
+                    if (!foundUsers.isEmpty()) {
+                        userIds.add(foundUsers.get(0).getId());
+                    }
+                }
+            }
+        }
+
+        boolean continueOnError
+                = 
exchange.getIn().getHeader(KeycloakConstants.CONTINUE_ON_ERROR, Boolean.FALSE, 
Boolean.class);
+        List<Map<String, Object>> results = new ArrayList<>();
+        int successCount = 0;
+        int failureCount = 0;
+
+        for (String userId : userIds) {
+            Map<String, Object> result = new HashMap<>();
+            result.put("userId", userId);
+            try {
+                
keycloakClient.realm(realmName).users().get(userId).roles().realmLevel().add(List.of(role));
+                result.put("status", "success");
+                successCount++;
+            } catch (Exception e) {
+                result.put("status", "failed");
+                result.put("error", e.getMessage());
+                failureCount++;
+                if (!continueOnError) {
+                    throw new RuntimeException("Failed to assign role to user: 
" + userId, e);
+                }
+            }
+            results.add(result);
+        }
+
+        Map<String, Object> summary = new HashMap<>();
+        summary.put("total", userIds.size());
+        summary.put("success", successCount);
+        summary.put("failed", failureCount);
+        summary.put("roleName", roleName);
+        summary.put("results", results);
+
+        Message message = getMessageForResponse(exchange);
+        message.setBody(summary);
+    }
+
+    private void bulkUpdateUsers(Keycloak keycloakClient, Exchange exchange) 
throws InvalidPayloadException {
+        String realmName = 
exchange.getIn().getHeader(KeycloakConstants.REALM_NAME, String.class);
+        if (ObjectHelper.isEmpty(realmName)) {
+            throw new IllegalArgumentException(MISSING_REALM_NAME);
+        }
+
+        List<UserRepresentation> users = 
exchange.getIn().getHeader(KeycloakConstants.USERS, List.class);
+        if (users == null || users.isEmpty()) {
+            // Try to get from body
+            Object payload = exchange.getIn().getMandatoryBody();
+            if (payload instanceof List) {
+                users = CastUtils.cast((List<?>) payload);
+            } else {
+                throw new IllegalArgumentException("Users list must be 
provided via header or body");
+            }
+        }
+
+        boolean continueOnError
+                = 
exchange.getIn().getHeader(KeycloakConstants.CONTINUE_ON_ERROR, Boolean.FALSE, 
Boolean.class);
+        List<Map<String, Object>> results = new ArrayList<>();
+        int successCount = 0;
+        int failureCount = 0;
+
+        for (UserRepresentation user : users) {
+            Map<String, Object> result = new HashMap<>();
+            result.put("userId", user.getId());
+            result.put("username", user.getUsername());
+            try {
+                if (ObjectHelper.isEmpty(user.getId())) {
+                    throw new IllegalArgumentException("User ID is required 
for update operation");
+                }
+                
keycloakClient.realm(realmName).users().get(user.getId()).update(user);
+                result.put("status", "success");
+                successCount++;
+            } catch (Exception e) {
+                result.put("status", "failed");
+                result.put("error", e.getMessage());
+                failureCount++;
+                if (!continueOnError) {
+                    throw new RuntimeException("Failed to update user: " + 
user.getId(), e);
+                }
+            }
+            results.add(result);
+        }
+
+        Map<String, Object> summary = new HashMap<>();
+        summary.put("total", users.size());
+        summary.put("success", successCount);
+        summary.put("failed", failureCount);
+        summary.put("results", results);
+
+        Message message = getMessageForResponse(exchange);
+        message.setBody(summary);
+    }
+
     public static Message getMessageForResponse(final Exchange exchange) {
         return exchange.getMessage();
     }
diff --git 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/KeycloakEndpointBuilderFactory.java
 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/KeycloakEndpointBuilderFactory.java
index 1c7cda271641..d49f150ef56a 100644
--- 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/KeycloakEndpointBuilderFactory.java
+++ 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/KeycloakEndpointBuilderFactory.java
@@ -3040,6 +3040,80 @@ public interface KeycloakEndpointBuilderFactory {
         public String keycloakLifespan() {
             return "CamelKeycloakLifespan";
         }
+        /**
+         * The list of users for bulk operations.
+         * 
+         * The option is a: {@code
+         * java.util.List<org.keycloak.representations.idm.UserRepresentation>}
+         * type.
+         * 
+         * Group: common
+         * 
+         * @return the name of the header {@code KeycloakUsers}.
+         */
+        public String keycloakUsers() {
+            return "CamelKeycloakUsers";
+        }
+        /**
+         * The list of user IDs for bulk operations.
+         * 
+         * The option is a: {@code java.util.List<String>} type.
+         * 
+         * Group: common
+         * 
+         * @return the name of the header {@code KeycloakUserIds}.
+         */
+        public String keycloakUserIds() {
+            return "CamelKeycloakUserIds";
+        }
+        /**
+         * The list of usernames for bulk operations.
+         * 
+         * The option is a: {@code java.util.List<String>} type.
+         * 
+         * Group: common
+         * 
+         * @return the name of the header {@code KeycloakUsernames}.
+         */
+        public String keycloakUsernames() {
+            return "CamelKeycloakUsernames";
+        }
+        /**
+         * The list of role names for bulk operations.
+         * 
+         * The option is a: {@code java.util.List<String>} type.
+         * 
+         * Group: common
+         * 
+         * @return the name of the header {@code KeycloakRoleNames}.
+         */
+        public String keycloakRoleNames() {
+            return "CamelKeycloakRoleNames";
+        }
+        /**
+         * Continue on error during bulk operations.
+         * 
+         * The option is a: {@code Boolean} type.
+         * 
+         * Group: common
+         * 
+         * @return the name of the header {@code KeycloakContinueOnError}.
+         */
+        public String keycloakContinueOnError() {
+            return "CamelKeycloakContinueOnError";
+        }
+        /**
+         * Batch size for bulk operations.
+         * 
+         * The option is a: {@code Integer} type.
+         * 
+         * Group: common
+         * 
+         * @return the name of the header {@code KeycloakBatchSize}.
+         */
+        public String keycloakBatchSize() {
+            return "CamelKeycloakBatchSize";
+        }
     }
     static KeycloakEndpointBuilder endpointBuilder(String componentName, 
String path) {
         class KeycloakEndpointBuilderImpl extends AbstractEndpointBuilder 
implements KeycloakEndpointBuilder, AdvancedKeycloakEndpointBuilder {

Reply via email to