7.4 KiB
🔧 Refactoring UserServiceImpl - Gestion des Erreurs de Connexion
Date: 2025-12-18
📋 Problème Initial
NullPointerException dans createUser (ligne 196)
Symptôme : Lorsque le client REST ne peut pas se connecter au service Keycloak et retourne null, une NullPointerException se produit à la ligne 196 lors de l'appel à response.getStatus().
Cause : Aucune vérification de nullité pour l'objet Response retourné par usersResource.create(userRep).
✅ Solution Implémentée
1. Création d'une Exception Personnalisée
Fichier créé : lions-user-manager-server-impl-quarkus/src/main/java/dev/lions/user/manager/service/exception/KeycloakServiceException.java
Classes d'exception :
KeycloakServiceException: Exception de base pour les erreurs KeycloakKeycloakServiceException.ServiceUnavailableException: Pour les erreurs de connexion (503, 502)KeycloakServiceException.TimeoutException: Pour les timeouts (504)
Avantages :
- ✅ Messages d'erreur clairs et spécifiques
- ✅ Codes HTTP préservés pour le debugging
- ✅ Hiérarchie d'exceptions pour gestion fine
2. Méthode Utilitaire validateResponse
Fonction : Valide une réponse HTTP du service Keycloak.
Vérifications :
- ✅ Réponse non null
- ✅ Code de statut HTTP attendu
- ✅ Gestion des codes d'erreur (400, 401, 403, 404, 409, 500, 502, 503, 504)
Utilisation :
Response response = usersResource.create(userRep);
validateResponse(response, "création de l'utilisateur", Response.Status.CREATED.getStatusCode());
3. Méthode Utilitaire handleConnectionException
Fonction : Gère les exceptions de connexion et les convertit en KeycloakServiceException appropriée.
Détection automatique :
- ✅
ConnectException - ✅
SocketTimeoutException - ✅ Messages contenant "Connection", "timeout", "refused", "Unable to connect"
Utilisation :
catch (Exception e) {
handleConnectionException(e, "création de l'utilisateur");
}
4. Refactoring de createUser
Avant :
var response = usersResource.create(userRep);
if (response.getStatus() != 201) {
throw new RuntimeException("Échec de la création...");
}
Après :
Response response = usersResource.create(userRep);
// Vérifier si la réponse est null (erreur de connexion)
if (response == null) {
throw new KeycloakServiceException.ServiceUnavailableException(
"Impossible de se connecter au service Keycloak...");
}
// Vérifier le code de statut HTTP
int status = response.getStatus();
if (status != Response.Status.CREATED.getStatusCode()) {
// Gérer les différents codes d'erreur HTTP
if (status == 400) { ... }
else if (status == 409) { ... }
else if (status == 503 || status == 502) { ... }
// ...
}
Améliorations :
- ✅ Vérification de nullité avant
getStatus() - ✅ Vérification de
getLocation()avant utilisation - ✅ Gestion spécifique des codes HTTP d'erreur
- ✅ Messages d'erreur clairs et actionnables
5. Refactoring des Autres Méthodes
Méthodes refactorisées :
- ✅
createUser- Vérification Response null + codes HTTP - ✅
updateUser- Vérification UserResource et UserRepresentation null - ✅
deleteUser- Vérification UserResource et UserRepresentation null - ✅
activateUser- Vérification UserResource et UserRepresentation null - ✅
deactivateUser- Vérification UserResource et UserRepresentation null - ✅
sendVerificationEmail- Vérification UserResource null - ✅
logoutAllSessions- Vérification UserResource null + getUserSessions null - ✅
searchUsers- Utilisation dehandleConnectionException - ✅
getUserByUsername- Vérification users null - ✅
getUserByEmail- Vérification users null - ✅
getUserById- Utilisation dehandleConnectionException - ✅
setPassword- Utilisation dehandleConnectionException
📊 Gestion des Codes HTTP
Codes Gérés
| Code | Exception | Message |
|---|---|---|
| 400 | KeycloakServiceException |
"Données invalides" |
| 401 | KeycloakServiceException |
"Non autorisé" |
| 403 | KeycloakServiceException |
"Accès interdit" |
| 404 | KeycloakServiceException |
"Ressource non trouvée" |
| 409 | KeycloakServiceException |
"Conflit" |
| 500 | KeycloakServiceException |
"Erreur serveur interne Keycloak" |
| 502 | ServiceUnavailableException |
"Service Keycloak indisponible" |
| 503 | ServiceUnavailableException |
"Service Keycloak indisponible" |
| 504 | TimeoutException |
"Timeout lors de l'opération" |
| null | ServiceUnavailableException |
"Impossible de se connecter au service Keycloak" |
🔍 Détection des Erreurs de Connexion
Types d'Exceptions Détectées
-
Exceptions Java Standard :
ConnectExceptionSocketTimeoutException
-
Messages d'Erreur :
- Contient "Connection"
- Contient "timeout"
- Contient "refused"
- Contient "Unable to connect"
Exemple de Détection
catch (Exception e) {
String errorMessage = e.getMessage();
if (e instanceof ConnectException ||
e instanceof SocketTimeoutException ||
(errorMessage != null && errorMessage.contains("Connection"))) {
throw new KeycloakServiceException.ServiceUnavailableException(...);
}
}
🎯 Résultat
Avant
- ❌
NullPointerExceptionsi Response est null - ❌ Messages d'erreur génériques (
RuntimeException) - ❌ Pas de distinction entre types d'erreurs
- ❌ Pas de gestion des codes HTTP spécifiques
Après
- ✅ Vérification de nullité systématique
- ✅ Exceptions spécifiques avec messages clairs
- ✅ Distinction entre erreurs de connexion, validation, autorisation, etc.
- ✅ Gestion complète des codes HTTP
- ✅ Logs détaillés pour le debugging
📝 Exemple d'Utilisation
Cas 1 : Connexion Échouée (Response null)
Response response = usersResource.create(userRep);
if (response == null) {
throw new KeycloakServiceException.ServiceUnavailableException(
"Impossible de se connecter au service Keycloak pour créer l'utilisateur: " + user.getUsername());
}
Cas 2 : Code HTTP d'Erreur
int status = response.getStatus();
if (status == 409) {
throw new IllegalArgumentException("L'utilisateur existe déjà (conflit détecté par Keycloak)");
} else if (status == 503) {
throw new KeycloakServiceException.ServiceUnavailableException("Service Keycloak indisponible");
}
Cas 3 : Exception de Connexion
catch (Exception e) {
handleConnectionException(e, "création de l'utilisateur " + user.getUsername());
}
🔄 Migration des Autres Méthodes
Toutes les méthodes qui utilisent le client REST Keycloak ont été refactorisées pour :
- ✅ Vérifier les objets null retournés
- ✅ Utiliser
handleConnectionExceptionpour les erreurs - ✅ Lever des
KeycloakServiceExceptionau lieu deRuntimeException - ✅ Gérer spécifiquement les codes HTTP d'erreur
📚 Références
Document créé le: 2025-12-18