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");
}
}
}