Migration complète vers PrimeFaces Freya - Corrections des incompatibilités et intégration de primefaces-freya-extension
This commit is contained in:
245
REFACTORING_USER_SERVICE_ERROR_HANDLING.md
Normal file
245
REFACTORING_USER_SERVICE_ERROR_HANDLING.md
Normal file
@@ -0,0 +1,245 @@
|
||||
# 🔧 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*
|
||||
|
||||
Reference in New Issue
Block a user