using CredentialManager.Models; using DataConnection.EF; using DataConnection.Interfaces; using DataConnection.REST.Interfaces; using DataConnection.REST.Implementations; using DataConnection.REST.Configuration; using DataConnection.CredentialManagement.Interfaces; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; namespace Data_Coupler.Services { /// /// Factory service per creare istanze di DatabaseManager e RestClient /// public interface IDataConnectionFactory { /// /// Crea un DatabaseManager per la credenziale specificata /// Task CreateDatabaseManagerAsync(string credentialName); /// /// Crea un RestServiceClient per la credenziale specificata /// Task CreateRestServiceClientAsync(string credentialName); /// /// Crea un RestMetadataDiscovery per la credenziale specificata /// Task CreateRestMetadataDiscoveryAsync(string credentialName); /// /// Pulisce la cache del client REST per una credenziale specifica /// void ClearRestClientCache(string credentialName); /// /// Pulisce tutta la cache dei client REST /// void ClearAllRestClientCache(); } public class DataConnectionFactory : IDataConnectionFactory { private readonly IServiceProvider _serviceProvider; private readonly ILogger _logger; private readonly IDataConnectionCredentialService _credentialService; // Cache per mantenere le istanze dei client REST autenticati private readonly Dictionary _restClientCache = new(); public DataConnectionFactory(IServiceProvider serviceProvider, ILogger logger, IDataConnectionCredentialService credentialService) { _serviceProvider = serviceProvider; _logger = logger; _credentialService = credentialService; }public async Task CreateDatabaseManagerAsync(string credentialName) { try { var credential = await _credentialService.GetDatabaseCredentialAsync(credentialName); if (credential == null) { throw new ArgumentException($"Credenziale database '{credentialName}' non trovata"); } var dbManagerOptions = await _credentialService.GetDbManagerOptionsAsync(credential.Name); return new EFCoreDatabaseManager(dbManagerOptions); } catch (Exception ex) { _logger.LogError(ex, "Errore nella creazione del DatabaseManager per {CredentialName}", credentialName); throw; } } public async Task CreateRestServiceClientAsync(string credentialName) { try { // Controlla se abbiamo già un client cached per questa credenziale if (_restClientCache.TryGetValue(credentialName, out var cachedClient)) { _logger.LogInformation("Utilizzando client REST cached per {CredentialName}", credentialName); return cachedClient; } var credential = await _credentialService.GetRestApiCredentialAsync(credentialName); if (credential == null) { throw new ArgumentException($"Credenziale REST API '{credentialName}' non trovata"); } var options = new RestServiceOptions { BaseUrl = credential.BaseUrl, Username = credential.Username, Password = credential.Password, TimeoutSeconds = credential.TimeoutSeconds, IgnoreSslErrors = credential.IgnoreSslErrors }; // Mapping specifico per tipo di servizio switch (credential.ServiceType) { case RestServiceType.Salesforce: // Per Salesforce usiamo i campi specifici ClientId e ClientSecret options.ApiKey = credential.ClientId; // ClientId -> ApiKey options.AuthToken = credential.ClientSecret; // ClientSecret -> AuthToken _logger.LogInformation("Salesforce mapping - ClientId: {ClientId}, ClientSecret: {HasSecret}, Username: {Username}", credential.ClientId, !string.IsNullOrEmpty(credential.ClientSecret), credential.Username); break; case RestServiceType.SapB1ServiceLayer: // Per SAP B1 usiamo il CompanyDatabase come ApiKey options.ApiKey = credential.CompanyDatabase; options.AuthToken = credential.AuthToken; _logger.LogInformation("SAP B1 mapping - CompanyDB: {CompanyDB}, Username: {Username}", credential.CompanyDatabase, credential.Username); break; default: // Per servizi generici usiamo ApiKey e AuthToken direttamente options.ApiKey = credential.ApiKey; options.AuthToken = credential.AuthToken; _logger.LogInformation("Generic mapping - ApiKey: {ApiKey}, AuthToken: {HasToken}, Username: {Username}", credential.ApiKey, !string.IsNullOrEmpty(credential.AuthToken), credential.Username); break; } var client = credential.ServiceType switch { RestServiceType.SapB1ServiceLayer => new SapB1ServiceClient(options), RestServiceType.Salesforce => CreateSalesforceClient(options), RestServiceType.Generic => CreateGenericRestClient(options), _ => throw new NotSupportedException($"Tipo di servizio REST non supportato: {credential.ServiceType}") }; // Salva il client nella cache _restClientCache[credentialName] = client; _logger.LogInformation("Client REST creato e cached per {CredentialName}", credentialName); return client; } catch (Exception ex) { _logger.LogError(ex, "Errore nella creazione del RestServiceClient per {CredentialName}", credentialName); throw; } } public async Task CreateRestMetadataDiscoveryAsync(string credentialName) { try { // Utilizza lo stesso client REST cached (che è già autenticato) var restClient = await CreateRestServiceClientAsync(credentialName); // I service client già implementano IRestMetadataDiscovery if (restClient is IRestMetadataDiscovery metadataDiscovery) { _logger.LogInformation("Utilizzando lo stesso client REST per metadata discovery per {CredentialName}", credentialName); return metadataDiscovery; } var credential = await _credentialService.GetRestApiCredentialAsync(credentialName); throw new NotSupportedException($"Il servizio REST {credential?.ServiceType} non supporta il metadata discovery"); } catch (Exception ex) { _logger.LogError(ex, "Errore nella creazione del RestMetadataDiscovery per {CredentialName}", credentialName); throw; } } private IRestServiceClient CreateGenericRestClient(RestServiceOptions options) { var httpClientFactory = _serviceProvider.GetRequiredService(); var httpClient = httpClientFactory.CreateClient(); return new BaseRestServiceClient(httpClient, options); } private IRestServiceClient CreateSalesforceClient(RestServiceOptions options) { var httpClientFactory = _serviceProvider.GetRequiredService(); var httpClient = httpClientFactory.CreateClient(); return new SalesforceServiceClient(httpClient, options); } /// /// Pulisce la cache del client REST per una credenziale specifica /// public void ClearRestClientCache(string credentialName) { if (_restClientCache.Remove(credentialName)) { _logger.LogInformation("Cache del client REST rimossa per {CredentialName}", credentialName); } } /// /// Pulisce tutta la cache dei client REST /// public void ClearAllRestClientCache() { _restClientCache.Clear(); _logger.LogInformation("Cache di tutti i client REST pulita"); } } }