246 lines
7.4 KiB
Markdown
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*
|
|
|