CargoWise eAdapter Integration Patterns: Complete Developer Guide
CargoWise eAdapter is a powerful integration platform that enables seamless data exchange between CargoWise and external systems. As a developer working with logistics and supply chain systems, understanding eAdapter integration patterns is crucial for building robust, scalable solutions. In this comprehensive guide, we'll explore the most effective integration patterns, best practices, and real-world implementation examples.
Understanding CargoWise eAdapter
What is eAdapter?
CargoWise eAdapter is an enterprise integration platform that provides:
- Real-time data synchronization - Bidirectional data flow between systems
- Event-driven architecture - Reactive integration based on business events
- Data transformation - Convert between different data formats and structures
- Error handling and retry logic - Robust error management and recovery
- Monitoring and logging - Comprehensive visibility into integration health
Key Components
- eAdapter Server - Central integration engine
- eAdapter Studio - Visual integration design tool
- eAdapter Runtime - Execution environment for integrations
- eAdapter Monitor - Real-time monitoring and management
- eAdapter SDK - Development tools and libraries
Integration Architecture Patterns
1. Point-to-Point Integration
Direct integration between CargoWise and a single external system.
// Point-to-point integration example
public class CargoWisePointToPointIntegration
{
    private readonly ICargoWiseService _cargoWiseService;
    private readonly IExternalSystemService _externalSystemService;
    private readonly ILogger<CargoWisePointToPointIntegration> _logger;
    
    public async Task SyncShipmentDataAsync(string shipmentId)
    {
        try
        {
            // Get data from CargoWise
            var shipment = await _cargoWiseService.GetShipmentAsync(shipmentId);
            
            // Transform data for external system
            var transformedData = TransformShipmentData(shipment);
            
            // Send to external system
            await _externalSystemService.UpdateShipmentAsync(transformedData);
            
            _logger.LogInformation("Successfully synced shipment {ShipmentId}", shipmentId);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to sync shipment {ShipmentId}", shipmentId);
            throw;
        }
    }
    
    private ExternalShipmentData TransformShipmentData(CargoWiseShipment shipment)
    {
        return new ExternalShipmentData
        {
            Id = shipment.ShipmentId,
            Status = MapStatus(shipment.Status),
            Origin = shipment.OriginPort,
            Destination = shipment.DestinationPort,
            EstimatedArrival = shipment.Eta,
            ActualArrival = shipment.Ata,
            Weight = shipment.TotalWeight,
            Volume = shipment.TotalVolume
        };
    }
}
2. Hub-and-Spoke Integration
Central integration hub managing multiple external systems.
// Hub-and-spoke integration pattern
public class IntegrationHub
{
    private readonly Dictionary<string, IExternalSystemService> _externalSystems;
    private readonly ICargoWiseService _cargoWiseService;
    private readonly IIntegrationOrchestrator _orchestrator;
    
    public async Task ProcessCargoWiseEventAsync(CargoWiseEvent cargoWiseEvent)
    {
        var integrationTasks = new List<Task>();
        
        // Determine which systems need to be updated
        var targetSystems = DetermineTargetSystems(cargoWiseEvent);
        
        foreach (var system in targetSystems)
        {
            integrationTasks.Add(ProcessEventForSystem(cargoWiseEvent, system));
        }
        
        // Process all integrations in parallel
        await Task.WhenAll(integrationTasks);
    }
    
    private async Task ProcessEventForSystem(CargoWiseEvent cargoWiseEvent, string systemName)
    {
        try
        {
            var system = _externalSystems[systemName];
            var transformedData = await TransformDataForSystem(cargoWiseEvent, systemName);
            await system.ProcessEventAsync(transformedData);
        }
        catch (Exception ex)
        {
            await _orchestrator.HandleIntegrationErrorAsync(cargoWiseEvent, systemName, ex);
        }
    }
}
3. Event-Driven Integration
Reactive integration based on CargoWise events.
// Event-driven integration pattern
public class EventDrivenIntegration
{
    private readonly IEventBus _eventBus;
    private readonly IIntegrationService _integrationService;
    
    public void ConfigureEventHandlers()
    {
        _eventBus.Subscribe<ShipmentCreatedEvent>(HandleShipmentCreated);
        _eventBus.Subscribe<ShipmentUpdatedEvent>(HandleShipmentUpdated);
        _eventBus.Subscribe<ShipmentStatusChangedEvent>(HandleShipmentStatusChanged);
    }
    
    private async Task HandleShipmentCreated(ShipmentCreatedEvent @event)
    {
        await _integrationService.CreateShipmentInExternalSystemsAsync(@event.Shipment);
    }
    
    private async Task HandleShipmentUpdated(ShipmentUpdatedEvent @event)
    {
        await _integrationService.UpdateShipmentInExternalSystemsAsync(@event.Shipment);
    }
    
    private async Task HandleShipmentStatusChanged(ShipmentStatusChangedEvent @event)
    {
        await _integrationService.NotifyExternalSystemsOfStatusChangeAsync(
            @event.ShipmentId, @event.NewStatus);
    }
}
Data Transformation Patterns
1. Mapping-Based Transformation
// Mapping-based data transformation
public class DataMappingService
{
    private readonly Dictionary<string, IDataMapper> _mappers;
    
    public TTarget Transform<TSource, TTarget>(TSource source, string mappingName)
    {
        var mapper = _mappers[mappingName];
        return mapper.Map<TSource, TTarget>(source);
    }
}
public class ShipmentDataMapper : IDataMapper
{
    public TTarget Map<TSource, TTarget>(TSource source)
    {
        if (source is CargoWiseShipment cargoWiseShipment && typeof(TTarget) == typeof(ExternalShipmentData))
        {
            return (TTarget)(object)MapToExternalShipment(cargoWiseShipment);
        }
        
        throw new NotSupportedException($"Mapping from {typeof(TSource)} to {typeof(TTarget)} not supported");
    }
    
    private ExternalShipmentData MapToExternalShipment(CargoWiseShipment shipment)
    {
        return new ExternalShipmentData
        {
            Id = shipment.ShipmentId,
            Reference = shipment.Reference,
            Status = MapShipmentStatus(shipment.Status),
            Origin = MapLocation(shipment.Origin),
            Destination = MapLocation(shipment.Destination),
            Cargo = MapCargo(shipment.Cargo),
            Dates = MapDates(shipment.Dates),
            Parties = MapParties(shipment.Parties)
        };
    }
}
2. Rule-Based Transformation
// Rule-based data transformation
public class RuleBasedTransformationService
{
    private readonly List<ITransformationRule> _rules;
    
    public TTarget Transform<TSource, TTarget>(TSource source)
    {
        var context = new TransformationContext<TSource, TTarget>(source);
        
        foreach (var rule in _rules)
        {
            if (rule.CanApply(context))
            {
                rule.Apply(context);
            }
        }
        
        return context.Result;
    }
}
public class StatusMappingRule : ITransformationRule
{
    private readonly Dictionary<string, string> _statusMapping = new()
    {
        { "BOOKED", "CONFIRMED" },
        { "IN_TRANSIT", "SHIPPED" },
        { "DELIVERED", "COMPLETED" },
        { "CANCELLED", "CANCELLED" }
    };
    
    public bool CanApply<T>(TransformationContext<T> context)
    {
        return context.Source is CargoWiseShipment;
    }
    
    public void Apply<T>(TransformationContext<T> context)
    {
        if (context.Source is CargoWiseShipment shipment)
        {
            var externalShipment = context.Result as ExternalShipmentData;
            externalShipment.Status = _statusMapping.GetValueOrDefault(shipment.Status, "UNKNOWN");
        }
    }
}
3. Template-Based Transformation
// Template-based data transformation
public class TemplateTransformationService
{
    private readonly ITemplateEngine _templateEngine;
    
    public string TransformToXml<T>(T data, string templateName)
    {
        var template = LoadTemplate(templateName);
        return _templateEngine.Render(template, data);
    }
    
    public T TransformFromXml<T>(string xml, string templateName)
    {
        var template = LoadTemplate(templateName);
        return _templateEngine.Parse<T>(xml, template);
    }
}
// XML template example
public class ShipmentXmlTemplate
{
    public const string ShipmentTemplate = @"
        <Shipment>
            <Id>{{ShipmentId}}</Id>
            <Reference>{{Reference}}</Reference>
            <Status>{{Status}}</Status>
            <Origin>
                <Port>{{Origin.Port}}</Port>
                <Country>{{Origin.Country}}</Country>
            </Origin>
            <Destination>
                <Port>{{Destination.Port}}</Port>
                <Country>{{Destination.Country}}</Country>
            </Destination>
            <Cargo>
                {{#each Cargo}}
                <Item>
                    <Description>{{Description}}</Description>
                    <Weight>{{Weight}}</Weight>
                    <Volume>{{Volume}}</Volume>
                </Item>
                {{/each}}
            </Cargo>
        </Shipment>";
}
Error Handling and Retry Patterns
1. Circuit Breaker Pattern
// Circuit breaker pattern for eAdapter integrations
public class CircuitBreakerIntegrationService
{
    private readonly CircuitBreakerPolicy _circuitBreaker;
    private readonly IIntegrationService _integrationService;
    
    public CircuitBreakerIntegrationService()
    {
        _circuitBreaker = Policy
            .Handle<Exception>()
            .CircuitBreakerAsync(
                exceptionsAllowedBeforeBreaking: 3,
                durationOfBreak: TimeSpan.FromMinutes(5),
                onBreak: (exception, duration) => 
                {
                    Console.WriteLine($"Circuit breaker opened for {duration}");
                },
                onReset: () => 
                {
                    Console.WriteLine("Circuit breaker reset");
                });
    }
    
    public async Task ProcessIntegrationAsync(IntegrationRequest request)
    {
        await _circuitBreaker.ExecuteAsync(async () =>
        {
            await _integrationService.ProcessAsync(request);
        });
    }
}
2. Retry with Exponential Backoff
// Retry pattern with exponential backoff
public class RetryIntegrationService
{
    private readonly IIntegrationService _integrationService;
    private readonly IAsyncPolicy _retryPolicy;
    
    public RetryIntegrationService()
    {
        _retryPolicy = Policy
            .Handle<HttpRequestException>()
            .Or<TimeoutException>()
            .WaitAndRetryAsync(
                retryCount: 3,
                sleepDurationProvider: retryAttempt => 
                    TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
                onRetry: (outcome, timespan, retryCount, context) =>
                {
                    Console.WriteLine($"Retry {retryCount} in {timespan}");
                });
    }
    
    public async Task ProcessIntegrationAsync(IntegrationRequest request)
    {
        await _retryPolicy.ExecuteAsync(async () =>
        {
            await _integrationService.ProcessAsync(request);
        });
    }
}
3. Dead Letter Queue Pattern
// Dead letter queue pattern for failed integrations
public class DeadLetterQueueService
{
    private readonly IMessageQueue _deadLetterQueue;
    private readonly ILogger<DeadLetterQueueService> _logger;
    
    public async Task HandleFailedIntegrationAsync(IntegrationRequest request, Exception exception)
    {
        var deadLetterMessage = new DeadLetterMessage
        {
            OriginalRequest = request,
            Exception = exception,
            Timestamp = DateTime.UtcNow,
            RetryCount = request.RetryCount
        };
        
        await _deadLetterQueue.SendAsync(deadLetterMessage);
        
        _logger.LogError(exception, "Integration failed and sent to dead letter queue: {RequestId}", 
            request.Id);
    }
    
    public async Task ProcessDeadLetterMessagesAsync()
    {
        var messages = await _deadLetterQueue.ReceiveAsync<DeadLetterMessage>();
        
        foreach (var message in messages)
        {
            if (ShouldRetry(message))
            {
                await RetryIntegrationAsync(message.OriginalRequest);
            }
            else
            {
                await HandlePermanentFailureAsync(message);
            }
        }
    }
}
Monitoring and Observability
1. Integration Health Monitoring
// Integration health monitoring
public class IntegrationHealthMonitor
{
    private readonly IHealthCheckService _healthCheckService;
    private readonly ILogger<IntegrationHealthMonitor> _logger;
    
    public async Task<IntegrationHealthStatus> CheckHealthAsync()
    {
        var healthChecks = new List<HealthCheckResult>();
        
        // Check CargoWise connectivity
        healthChecks.Add(await CheckCargoWiseConnectivityAsync());
        
        // Check external system connectivity
        healthChecks.Add(await CheckExternalSystemConnectivityAsync());
        
        // Check integration queue health
        healthChecks.Add(await CheckIntegrationQueueHealthAsync());
        
        // Check data transformation health
        healthChecks.Add(await CheckDataTransformationHealthAsync());
        
        return new IntegrationHealthStatus
        {
            OverallHealth = healthChecks.All(h => h.IsHealthy) ? HealthStatus.Healthy : HealthStatus.Unhealthy,
            Checks = healthChecks,
            Timestamp = DateTime.UtcNow
        };
    }
    
    private async Task<HealthCheckResult> CheckCargoWiseConnectivityAsync()
    {
        try
        {
            // Implement CargoWise connectivity check
            var isConnected = await TestCargoWiseConnectionAsync();
            return new HealthCheckResult
            {
                Name = "CargoWise Connectivity",
                IsHealthy = isConnected,
                Message = isConnected ? "Connected" : "Connection failed"
            };
        }
        catch (Exception ex)
        {
            return new HealthCheckResult
            {
                Name = "CargoWise Connectivity",
                IsHealthy = false,
                Message = ex.Message
            };
        }
    }
}
2. Performance Metrics
// Performance metrics collection
public class IntegrationMetricsService
{
    private readonly IMetricsCollector _metricsCollector;
    
    public async Task<T> TrackIntegrationCallAsync<T>(string operationName, Func<Task<T>> operation)
    {
        var stopwatch = Stopwatch.StartNew();
        
        try
        {
            var result = await operation();
            stopwatch.Stop();
            
            _metricsCollector.RecordSuccess(operationName, stopwatch.ElapsedMilliseconds);
            return result;
        }
        catch (Exception ex)
        {
            stopwatch.Stop();
            _metricsCollector.RecordFailure(operationName, stopwatch.ElapsedMilliseconds, ex);
            throw;
        }
    }
    
    public void RecordDataVolume(string integrationName, int recordCount, long dataSize)
    {
        _metricsCollector.RecordGauge("integration.data.records", recordCount, 
            new Dictionary<string, string> { ["integration"] = integrationName });
        _metricsCollector.RecordGauge("integration.data.size", dataSize, 
            new Dictionary<string, string> { ["integration"] = integrationName });
    }
}
Security Patterns
1. Authentication and Authorization
// Authentication and authorization for eAdapter integrations
public class SecureIntegrationService
{
    private readonly IAuthenticationService _authService;
    private readonly IAuthorizationService _authorizationService;
    
    public async Task<IntegrationResponse> ProcessSecureIntegrationAsync(
        IntegrationRequest request, string userToken)
    {
        // Authenticate user
        var user = await _authService.ValidateTokenAsync(userToken);
        if (user == null)
        {
            throw new UnauthorizedAccessException("Invalid user token");
        }
        
        // Authorize integration operation
        var authResult = await _authorizationService.AuthorizeAsync(
            user, request.Operation, request.Resource);
            
        if (!authResult.Succeeded)
        {
            throw new UnauthorizedAccessException("Insufficient permissions");
        }
        
        // Process integration with user context
        return await ProcessIntegrationWithUserContextAsync(request, user);
    }
}
2. Data Encryption
// Data encryption for sensitive integration data
public class EncryptedIntegrationService
{
    private readonly IEncryptionService _encryptionService;
    private readonly IIntegrationService _integrationService;
    
    public async Task ProcessEncryptedIntegrationAsync(IntegrationRequest request)
    {
        // Encrypt sensitive data
        var encryptedRequest = await EncryptSensitiveDataAsync(request);
        
        // Process integration
        var response = await _integrationService.ProcessAsync(encryptedRequest);
        
        // Decrypt response
        return await DecryptSensitiveDataAsync(response);
    }
    
    private async Task<IntegrationRequest> EncryptSensitiveDataAsync(IntegrationRequest request)
    {
        return new IntegrationRequest
        {
            Id = request.Id,
            Operation = request.Operation,
            Data = await _encryptionService.EncryptAsync(request.Data),
            Metadata = request.Metadata
        };
    }
}
Testing Strategies
1. Unit Testing
[Test]
public async Task TransformShipmentData_ShouldMapCorrectly()
{
    // Arrange
    var mapper = new ShipmentDataMapper();
    var cargoWiseShipment = new CargoWiseShipment
    {
        ShipmentId = "SH001",
        Status = "BOOKED",
        Origin = new Location { Port = "LAX", Country = "US" },
        Destination = new Location { Port = "LHR", Country = "GB" }
    };
    
    // Act
    var result = mapper.Map<CargoWiseShipment, ExternalShipmentData>(cargoWiseShipment);
    
    // Assert
    Assert.AreEqual("SH001", result.Id);
    Assert.AreEqual("CONFIRMED", result.Status);
    Assert.AreEqual("LAX", result.Origin.Port);
    Assert.AreEqual("LHR", result.Destination.Port);
}
2. Integration Testing
[Test]
public async Task ProcessIntegration_ShouldSucceed()
{
    // Arrange
    var integrationService = new IntegrationService();
    var request = new IntegrationRequest
    {
        Id = Guid.NewGuid().ToString(),
        Operation = "CREATE_SHIPMENT",
        Data = CreateTestShipmentData()
    };
    
    // Act
    var response = await integrationService.ProcessAsync(request);
    
    // Assert
    Assert.IsTrue(response.Success);
    Assert.IsNotNull(response.ExternalId);
}
3. Load Testing
[Test]
public async Task ProcessMultipleIntegrations_ShouldHandleLoad()
{
    // Arrange
    var integrationService = new IntegrationService();
    var requests = Enumerable.Range(0, 1000)
        .Select(i => new IntegrationRequest
        {
            Id = Guid.NewGuid().ToString(),
            Operation = "UPDATE_SHIPMENT",
            Data = CreateTestShipmentData()
        })
        .ToList();
    
    // Act
    var tasks = requests.Select(r => integrationService.ProcessAsync(r));
    var responses = await Task.WhenAll(tasks);
    
    // Assert
    Assert.AreEqual(1000, responses.Length);
    Assert.IsTrue(responses.All(r => r.Success));
}
Best Practices
1. Design Principles
- Single Responsibility - Each integration component should have one clear purpose
- Loose Coupling - Minimize dependencies between integration components
- High Cohesion - Related functionality should be grouped together
- Fail Fast - Detect and handle errors early in the integration process
2. Performance Optimization
- Batch Processing - Process multiple records together when possible
- Asynchronous Processing - Use async/await for I/O operations
- Caching - Cache frequently accessed data
- Connection Pooling - Reuse database and HTTP connections
3. Error Handling
- Graceful Degradation - Continue processing when non-critical errors occur
- Retry Logic - Implement intelligent retry mechanisms
- Dead Letter Queues - Handle permanently failed messages
- Circuit Breakers - Prevent cascading failures
4. Monitoring and Logging
- Comprehensive Logging - Log all integration activities
- Performance Metrics - Track integration performance
- Health Checks - Monitor integration health
- Alerting - Set up alerts for critical issues
Conclusion
CargoWise eAdapter integration patterns provide a robust foundation for building scalable, maintainable logistics integrations. By following these patterns and best practices, you can create integrations that are reliable, performant, and secure.
Key takeaways:
- Choose the right integration pattern for your use case
- Implement proper error handling and retry logic
- Use comprehensive monitoring and logging
- Follow security best practices
- Test thoroughly at all levels
Ready to build your CargoWise eAdapter integration? Our team at Elysiate has extensive experience with logistics integrations and can help you implement the right patterns for your specific needs. Contact us to learn more about our integration services.
Need help with other enterprise integration challenges? Explore our services to see how we can help your organization succeed.