This repository has been archived on 2026-01-03. You can view files and clone it, but cannot push or open issues or pull requests.
Files
lions-user-manager/REFACTORING_USER_SERVICE_ERROR_HANDLING.md

246 lines
7.4 KiB
Markdown

# 🔧 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 Keycloak
- `KeycloakServiceException.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** :
```java
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** :
```java
catch (Exception e) {
handleConnectionException(e, "création de l'utilisateur");
}
```
---
### 4. Refactoring de `createUser`
**Avant** :
```java
var response = usersResource.create(userRep);
if (response.getStatus() != 201) {
throw new RuntimeException("Échec de la création...");
}
```
**Après** :
```java
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 de `handleConnectionException`
-`getUserByUsername` - Vérification users null
-`getUserByEmail` - Vérification users null
-`getUserById` - Utilisation de `handleConnectionException`
-`setPassword` - Utilisation de `handleConnectionException`
---
## 📊 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
1. **Exceptions Java Standard** :
- `ConnectException`
- `SocketTimeoutException`
2. **Messages d'Erreur** :
- Contient "Connection"
- Contient "timeout"
- Contient "refused"
- Contient "Unable to connect"
### Exemple de Détection
```java
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
-`NullPointerException` si 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)
```java
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
```java
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
```java
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 :
1. ✅ Vérifier les objets null retournés
2. ✅ Utiliser `handleConnectionException` pour les erreurs
3. ✅ Lever des `KeycloakServiceException` au lieu de `RuntimeException`
4. ✅ Gérer spécifiquement les codes HTTP d'erreur
---
## 📚 Références
- [Keycloak Admin Client Documentation](https://www.keycloak.org/docs/latest/server_development/#admin-rest-api)
- [JAX-RS Response API](https://jakarta.ee/specifications/restful-ws/3.0/jakarta-restful-ws-spec-3.0.html#response)
- [Java Exception Handling Best Practices](https://docs.oracle.com/javase/tutorial/essential/exceptions/)
---
*Document créé le: 2025-12-18*