# 🔧 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*

