Integration Patterns and Middleware

Level: Expert Module: Architecture 24 min read Lesson 41 of 47

Overview

  • What you’ll learn:
    • How to connect iDempiere with external systems using integration architecture patterns including point-to-point, hub-and-spoke, ESB, and event-driven approaches
    • How to implement EDI processing, message queue integration, and RESTful API patterns for reliable system-to-system communication
    • How to handle errors, retries, and idempotency in integration workflows, with a practical e-commerce integration example
  • Prerequisites: Lesson 40 — System Architecture Design, familiarity with REST APIs and messaging concepts
  • Estimated reading time: 25 minutes

Introduction

No ERP system operates in isolation. In a modern enterprise, iDempiere must exchange data with e-commerce platforms, CRM systems, warehouse management systems, payment gateways, banking interfaces, government tax portals, and countless other applications. The way you design these integrations — the patterns you choose, the error handling you implement, and the data transformations you manage — determines whether your integrations are reliable and maintainable or fragile and unpredictable.

This lesson covers the foundational integration patterns and technologies you will encounter when connecting iDempiere to the outside world. We will move from architectural theory to practical implementation, culminating in a worked example of integrating iDempiere with an e-commerce platform.

Integration Architecture Patterns

Before diving into specific technologies, it is important to understand the architectural patterns that govern how systems communicate. Choosing the right pattern shapes everything that follows.

Point-to-Point Integration

Each system connects directly to every other system it needs to communicate with. System A talks to System B, System B talks to System C, and so on.

  • Advantages: Simplest to implement for a small number of connections. No middleware infrastructure required. Low latency (direct communication).
  • Disadvantages: The number of connections grows exponentially — N systems require up to N(N-1)/2 connections. Tightly couples systems together. A change in one system’s API requires updates in every connected system. Becomes unmanageable beyond 4-5 integrated systems.
  • When to use: When you have only 2-3 systems to integrate and the integration requirements are simple and unlikely to change.

Hub-and-Spoke (Message Broker)

A central hub routes messages between systems. Each system connects only to the hub, not to every other system. The hub handles message routing, transformation, and delivery.

  • Advantages: Reduces connection complexity to N connections (one per system). Centralizes message routing and transformation logic. Easier to add new systems — connect them to the hub.
  • Disadvantages: The hub is a single point of failure (must be made highly available). All traffic flows through the hub, which can become a bottleneck. Hub-specific knowledge required.
  • When to use: Medium-complexity integration landscapes with 5-15 systems. When you need centralized message transformation and routing.

Enterprise Service Bus (ESB)

An evolution of hub-and-spoke, the ESB distributes integration logic across a bus rather than concentrating it in a single hub. It provides routing, transformation, protocol mediation, and orchestration as a shared infrastructure service.

  • Advantages: Handles complex integration scenarios (protocol conversion, content-based routing, orchestration). Enterprise-grade reliability and monitoring. Standard tooling for non-developers to manage integrations.
  • Disadvantages: Significant infrastructure and licensing cost. Complex to set up and maintain. Can become a monolithic bottleneck if not carefully managed. Often seen as heavyweight for modern architectures.
  • When to use: Large enterprises with diverse integration requirements across many systems and protocols. Organizations with dedicated integration teams.

Event-Driven Architecture (EDA)

Systems publish events (notifications of state changes) to a shared event bus or message broker. Other systems subscribe to events they care about and react independently. There is no direct coupling between publisher and subscriber.

  • Advantages: Loose coupling — publishers do not know or care who is listening. Naturally supports asynchronous processing. Highly scalable (add subscribers without affecting publishers). Enables real-time data flow.
  • Disadvantages: Eventual consistency (subscribers may process events at different rates). Harder to debug (no single request/response trace). Requires robust event infrastructure. Event ordering and deduplication must be handled.
  • When to use: Modern, microservices-oriented architectures. When multiple systems need to react to the same business events. When real-time data propagation is important.

EDI Standards and Processing

Electronic Data Interchange (EDI) is the automated exchange of structured business documents between organizations using standardized formats. Despite being decades old, EDI remains the dominant integration method for supply chain operations, especially in retail, manufacturing, and logistics.

EDI Standards

  • ANSI X12: The dominant EDI standard in North America. Documents are called Transaction Sets and identified by numbers — 850 (Purchase Order), 810 (Invoice), 856 (Advance Ship Notice), 997 (Functional Acknowledgment).
  • UN/EDIFACT: The international standard, widely used in Europe and Asia. Documents are called Messages — ORDERS (Purchase Order), INVOIC (Invoice), DESADV (Dispatch Advice).
  • XML-based EDI: Modern alternatives like cXML (commerce XML), UBL (Universal Business Language), and RosettaNet use XML instead of the traditional fixed-format segments. Easier to parse and validate, but less universally adopted in legacy supply chains.

EDI Processing in iDempiere

iDempiere does not include a native EDI engine, but the Import/Export framework provides the foundation for EDI processing. A typical EDI integration involves:

  1. Receive: Incoming EDI files arrive via AS2, SFTP, or a VAN (Value-Added Network). An EDI translator (either a standalone tool like Bots, or a cloud service like SPS Commerce or TrueCommerce) converts the raw EDI format into a structured format (CSV, XML, JSON).
  2. Import into iDempiere: The translated data is loaded into iDempiere’s import tables (I_Order, I_Invoice, I_BPartner) via CSV import or direct database insert. The Import Loader process then validates and creates the corresponding business documents.
  3. Export from iDempiere: Outbound documents (invoices, advance ship notices) are extracted from iDempiere using SQL queries or API calls, transformed into the required EDI format by the translator, and transmitted to the trading partner.

For organizations with high EDI volume, consider building a dedicated plugin that automates the receive-translate-import and export-translate-send workflows, including acknowledgment handling and error notification.

Message Queue Integration

Message queues provide asynchronous, reliable communication between systems. They decouple the sender from the receiver in both time and availability — the sender can publish a message even if the receiver is temporarily offline, and the receiver processes messages at its own pace.

Apache Kafka

Kafka is a distributed event streaming platform designed for high throughput and durability. Messages are organized into topics, and consumers read from topics using consumer groups. Key characteristics for iDempiere integration:

  • Durable message storage: Kafka retains messages on disk for a configurable period (days, weeks, or indefinitely), allowing consumers to replay events if needed.
  • Ordering guarantees: Messages within a partition are strictly ordered. Use a consistent partition key (e.g., business partner ID, document number) to ensure related messages are processed in order.
  • Consumer groups: Multiple instances of the same consumer can share the workload of processing a topic. Kafka automatically balances partitions across group members.
// Example: iDempiere plugin publishing order events to Kafka
Properties props = new Properties();
props.put("bootstrap.servers", "kafka-broker:9092");
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("acks", "all");  // Wait for all replicas to acknowledge

KafkaProducer<String, String> producer = new KafkaProducer<>(props);

// In a Model Validator after document completion
public String docValidate(PO po, int timing) {
    if (timing == TIMING_AFTER_COMPLETE && po instanceof MOrder) {
        MOrder order = (MOrder) po;
        String json = convertOrderToJson(order);
        ProducerRecord<String, String> record =
            new ProducerRecord<>("idempiere.orders",
                order.getDocumentNo(), json);
        producer.send(record);
    }
    return null;
}

RabbitMQ

RabbitMQ is a traditional message broker implementing the AMQP (Advanced Message Queuing Protocol) standard. It excels at routing messages using exchanges and bindings, supporting patterns like direct routing, topic-based routing, fan-out (broadcast), and headers-based routing.

  • Acknowledgments: Consumers explicitly acknowledge message processing. If a consumer dies before acknowledging, the message is redelivered to another consumer — guaranteeing at-least-once delivery.
  • Dead letter exchanges: Messages that cannot be processed (expired, rejected, or exceeding retry limits) are routed to a dead letter exchange for investigation.
  • Lighter weight than Kafka: Simpler to set up and operate for moderate message volumes. Better suited for traditional request-reply patterns and complex routing rules.

Asynchronous Processing Patterns

When integrating iDempiere with message queues, several patterns are essential:

  • Command pattern: The queue message represents an instruction to perform an action (e.g., “create this order”). The consumer validates the command, executes it, and publishes a result event.
  • Event notification pattern: The queue message announces that something happened (e.g., “order 12345 was completed”). Subscribers react independently to the event.
  • Request-reply pattern: The sender publishes a request message with a correlation ID and a reply-to queue. The consumer processes the request and publishes the response to the reply-to queue. The original sender correlates the response using the correlation ID.

RESTful API Integration

REST APIs are the most common integration method for modern web-based systems. iDempiere provides REST API capabilities through community plugins, and you will frequently need to integrate with external REST APIs.

iDempiere as an API Provider

The iDempiere REST API plugin exposes iDempiere data and operations as RESTful endpoints. Typical capabilities include:

  • CRUD operations: Create, read, update, and delete records in any iDempiere table via HTTP methods (POST, GET, PUT, DELETE).
  • Process execution: Trigger iDempiere processes via API calls, passing parameters and receiving results.
  • Document operations: Complete, void, reverse, and close documents through API endpoints.
  • Authentication: Token-based authentication (typically JWT) with role-based access control inherited from iDempiere’s security model.

iDempiere as an API Consumer

When iDempiere needs to call external APIs (e.g., fetching shipping rates, validating tax IDs, syncing inventory with a marketplace), implement the integration in a plugin using Java’s HTTP client libraries:

// Example: Calling an external API from an iDempiere plugin
HttpClient client = HttpClient.newBuilder()
    .connectTimeout(Duration.ofSeconds(10))
    .build();

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.shipping.example/v2/rates"))
    .header("Authorization", "Bearer " + apiToken)
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(requestJson))
    .timeout(Duration.ofSeconds(30))
    .build();

HttpResponse<String> response = client.send(request,
    HttpResponse.BodyHandlers.ofString());

if (response.statusCode() == 200) {
    // Parse and process the response
    JSONObject rates = new JSONObject(response.body());
    // Update iDempiere records with the fetched rates
}

SOAP Web Services (Legacy)

SOAP (Simple Object Access Protocol) web services use XML messaging with strict contracts defined in WSDL (Web Services Description Language). While SOAP has largely been replaced by REST for new integrations, you will encounter it when integrating with legacy enterprise systems, government portals, and older ERP systems.

  • iDempiere includes legacy SOAP web service support through the org.adempiere.webservices bundle.
  • SOAP services offer stronger typing, built-in error handling (SOAP faults), and WS-Security for enterprise authentication.
  • Use Java’s JAX-WS libraries or Apache CXF for SOAP client implementations in iDempiere plugins.

Webhook Patterns

Webhooks invert the polling model: instead of iDempiere periodically checking an external system for changes, the external system pushes notifications to iDempiere when events occur. Implementing webhook reception in iDempiere requires:

  1. A servlet or REST endpoint registered in iDempiere to receive incoming HTTP POST requests.
  2. Signature verification (typically HMAC-SHA256) to confirm the webhook came from the expected source.
  3. Immediate acknowledgment (return HTTP 200) followed by asynchronous processing to avoid timeout issues.
  4. Idempotency handling — webhooks may be delivered more than once.

Idempotency in Integrations

In distributed systems, messages can be delivered more than once due to network retries, consumer restarts, or message broker redelivery. Idempotency ensures that processing the same message multiple times has the same effect as processing it once.

Implementing Idempotency

  • Unique message identifiers: Assign each message a unique ID (UUID) at the source. Before processing, check if a message with that ID has already been processed. Store processed message IDs in a database table with a unique constraint.
  • Natural business keys: Use existing business identifiers (external order number, invoice number, shipment tracking number) as idempotency keys. Before creating a new document, check if one already exists with that external reference.
  • Database constraints: Rely on unique indexes in iDempiere tables as a safety net. For example, a unique index on (AD_Client_ID, DocumentNo, C_DocType_ID) prevents duplicate document creation.
// Idempotency check before processing an incoming order
String externalOrderId = incomingMessage.getExternalOrderId();

// Check if we already processed this order
String sql = "SELECT C_Order_ID FROM C_Order WHERE ExternalReference = ? AND AD_Client_ID = ?";
int existingOrderId = DB.getSQLValue(null, sql, externalOrderId, clientId);

if (existingOrderId > 0) {
    log.info("Order already exists for external ID " + externalOrderId + ", skipping");
    return; // Idempotent - no duplicate created
}

// Proceed with order creation
MOrder order = new MOrder(ctx, 0, null);
order.set_ValueOfColumn("ExternalReference", externalOrderId);
// ... populate order fields
order.saveEx();

Error Handling and Retry Strategies

Integration errors are inevitable. Network failures, service outages, data validation errors, and rate limits will all occur. A robust error handling strategy distinguishes reliable integrations from brittle ones.

Classifying Errors

  • Transient errors: Temporary failures that will resolve on their own — network timeouts, HTTP 503 (Service Unavailable), database connection pool exhaustion, rate limiting (HTTP 429). These should be retried.
  • Permanent errors: Failures that will not resolve without intervention — invalid data (HTTP 400), authentication failure (HTTP 401), resource not found (HTTP 404), business rule violations. These should not be retried but instead sent to a dead letter queue for investigation.

Retry with Exponential Backoff

For transient errors, retry the operation with increasing delays between attempts:

// Exponential backoff retry pattern
int maxRetries = 5;
long baseDelay = 1000; // 1 second

for (int attempt = 0; attempt < maxRetries; attempt++) {
    try {
        executeIntegration();
        break; // Success
    } catch (TransientException e) {
        if (attempt == maxRetries - 1) throw e; // Final attempt failed
        long delay = baseDelay * (long) Math.pow(2, attempt);
        // Add jitter to prevent thundering herd
        delay += ThreadLocalRandom.current().nextLong(0, delay / 2);
        Thread.sleep(delay);
        log.warning("Retry attempt " + (attempt + 1) + " after " + delay + "ms");
    }
}

Dead Letter Queues

Messages that fail processing after all retry attempts should be routed to a dead letter queue (DLQ) rather than being silently dropped. The DLQ serves as a holding area for investigation. Implement monitoring and alerting on DLQ depth, and build tooling to inspect, fix, and replay failed messages.

Circuit Breaker Pattern

If an external system is consistently failing, continuing to send requests wastes resources and may overwhelm the struggling system. The circuit breaker pattern tracks failure rates and “opens” the circuit (stops sending requests) when failures exceed a threshold. After a cooldown period, the circuit enters a “half-open” state where a single test request is allowed through. If it succeeds, the circuit closes (normal operation resumes); if it fails, the circuit opens again.

Data Transformation and Mapping

Data rarely flows between systems without transformation. iDempiere uses specific data formats, field lengths, reference values, and conventions that may differ significantly from external systems.

Common Transformation Tasks

  • Field mapping: External system field names and structures rarely match iDempiere’s. Maintain explicit mapping configurations (JSON, XML, or database tables) rather than hardcoding mappings in code.
  • Value translation: Convert external code values to iDempiere reference values (e.g., external status codes to iDempiere document statuses, external unit codes to iDempiere UOM IDs).
  • Data format conversion: Date formats, number formats, currency representations, and address structures vary across systems and regions.
  • Aggregation and splitting: An external order with 100 line items might need to be split into multiple iDempiere orders based on warehouse or organization rules. Conversely, multiple external events might need to be aggregated into a single iDempiere document.

Middleware Platforms

When integration complexity exceeds what you can reasonably manage with custom code, middleware platforms provide pre-built connectors, visual mapping tools, and operational monitoring.

Apache Camel

Apache Camel is an open-source integration framework that implements Enterprise Integration Patterns (EIP). It provides a domain-specific language (DSL) for defining message routes between endpoints. Camel supports over 300 components (connectors) for different systems and protocols.

// Apache Camel route: File pickup, transform, and send to iDempiere
from("file:/edi/incoming?noop=true")
    .unmarshal().csv()
    .process(exchange -> {
        // Transform CSV to iDempiere import format
        List<List<String>> rows = exchange.getIn().getBody(List.class);
        String importData = transformToIdempiere(rows);
        exchange.getIn().setBody(importData);
    })
    .to("jdbc:idempiere?useHeadersAsParameters=true")
    .log("Imported ${header.CamelFileName} into iDempiere")
    .to("file:/edi/processed");

MuleSoft and Other Commercial Options

MuleSoft Anypoint Platform, Dell Boomi, Microsoft Azure Integration Services, and AWS Step Functions provide cloud-based integration platforms with visual designers, pre-built connectors, and managed infrastructure. These are appropriate for large enterprises with diverse integration landscapes and the budget for commercial tooling. For smaller deployments, Apache Camel or custom plugin code is usually sufficient.

Practical Example: E-Commerce Integration

Let us walk through the design of a complete integration between iDempiere and an e-commerce platform (such as WooCommerce, Shopify, or Magento). This example combines multiple patterns covered in this lesson.

Integration Requirements

  • Products and inventory levels must be synchronized from iDempiere to the e-commerce platform.
  • Customer orders placed on the e-commerce platform must be created as Sales Orders in iDempiere.
  • Shipment tracking information from iDempiere must be pushed back to the e-commerce platform.
  • Customer records must be synchronized bidirectionally.

Architecture Design

Use an event-driven architecture with a message queue (Kafka or RabbitMQ) as the integration backbone:

  1. iDempiere Model Validators publish events to the message queue when products are updated, inventory changes, or shipments are completed.
  2. E-commerce webhooks push new order and customer events to a webhook receiver that publishes them to the message queue.
  3. Integration workers (consumer processes) subscribe to queue topics, transform the data between iDempiere and e-commerce formats, and call the appropriate APIs to synchronize the data.
  4. Error handling: Failed messages go to dead letter queues with alerting. A retry scheduler periodically attempts to reprocess failed messages.

Data Mapping Considerations

  • Map e-commerce product SKUs to iDempiere M_Product.Value (Search Key).
  • Map e-commerce customer email addresses to iDempiere C_BPartner records, creating new business partners for first-time customers.
  • Map e-commerce order statuses to iDempiere document actions (draft, complete, void).
  • Handle unit of measure conversions, currency conversions, and tax calculation differences between the systems.
  • Store external system IDs in iDempiere custom columns (e.g., ShopifyOrderID) for cross-reference and idempotency.

Inventory Synchronization Detail

Inventory synchronization requires particular care because stock levels change frequently and errors directly impact customer experience (overselling or underselling):

  1. An iDempiere Model Validator fires on M_Transaction (the table that records every inventory movement) after save.
  2. The validator calculates the new available quantity for the affected product-warehouse combination using MStorageOnHand.
  3. It publishes an inventory update event to the message queue with the product SKU, warehouse, and new quantity.
  4. The integration worker consumes the event and calls the e-commerce platform’s API to update the stock level.
  5. To handle rapid-fire inventory changes, the worker batches updates (e.g., only send the latest quantity for each SKU every 30 seconds) to avoid API rate limits.

Summary

Integration is where iDempiere meets the broader enterprise ecosystem. The patterns you choose — point-to-point vs. event-driven, synchronous vs. asynchronous, polling vs. webhook — should be driven by your specific requirements for reliability, latency, volume, and operational complexity. The key principles to remember are:

  • Design for failure — every integration will experience errors, so build in retries, dead letter queues, and circuit breakers from the start.
  • Ensure idempotency — duplicate messages are inevitable in distributed systems.
  • Prefer asynchronous patterns for better scalability and resilience.
  • Start simple (point-to-point) and evolve to more sophisticated patterns (event-driven, middleware) as complexity demands.
  • Document your data mappings thoroughly — they are the most common source of integration bugs.

In the next lesson, we will focus on authentication and Single Sign-On — how to secure your iDempiere deployment with LDAP, OAuth2, SAML, and custom authentication providers.

繁體中文

概述

  • 您將學到:
    • 如何使用整合架構模式(包括點對點、輪輻式、ESB 和事件驅動方法)將 iDempiere 與外部系統連接
    • 如何實作 EDI 處理、訊息佇列整合及 RESTful API 模式,以實現可靠的系統對系統通訊
    • 如何在整合工作流程中處理錯誤、重試與冪等性,並包含實際的電子商務整合範例
  • 先備知識:第 40 課 — 系統架構設計,熟悉 REST API 及訊息傳遞概念
  • 預估閱讀時間:25 分鐘

介紹

沒有任何 ERP 系統是獨立運作的。在現代企業中,iDempiere 必須與電子商務平台、CRM 系統、倉儲管理系統、支付閘道、銀行介面、政府稅務入口網站及無數其他應用程式交換資料。您設計這些整合的方式——您選擇的模式、您實作的錯誤處理、您管理的資料轉換——決定了您的整合是可靠且易於維護的,還是脆弱且不可預測的。

本課涵蓋了將 iDempiere 連接到外部世界時會遇到的基礎整合模式與技術。我們將從架構理論出發,進入實際實作,最終以一個將 iDempiere 與電子商務平台整合的完整範例作結。

整合架構模式

在深入探討特定技術之前,了解管理系統間通訊的架構模式非常重要。選擇正確的模式會影響後續的一切。

點對點整合

每個系統直接連接到它需要通訊的每個其他系統。系統 A 與系統 B 通訊,系統 B 與系統 C 通訊,依此類推。

  • 優點:對於少量連接來說最容易實作。不需要中介軟體基礎架構。低延遲(直接通訊)。
  • 缺點:連接數量呈指數增長——N 個系統最多需要 N(N-1)/2 個連接。系統之間緊密耦合。一個系統的 API 變更需要更新每個連接的系統。超過 4-5 個整合系統後變得難以管理。
  • 適用時機:當您只有 2-3 個系統需要整合,且整合需求簡單且不太可能變更時。

輪輻式架構(Message Broker)

一個中央樞紐在系統之間路由訊息。每個系統只連接到樞紐,而不是連接到每個其他系統。樞紐處理訊息路由、轉換和傳遞。

  • 優點:將連接複雜度降低為 N 個連接(每個系統一個)。集中化訊息路由和轉換邏輯。更容易新增系統——將它們連接到樞紐即可。
  • 缺點:樞紐是單一故障點(必須具備高可用性)。所有流量都經過樞紐,可能成為瓶頸。需要樞紐特定知識。
  • 適用時機:中等複雜度的整合環境,包含 5-15 個系統。當您需要集中化的訊息轉換和路由時。

Enterprise Service Bus (ESB)

ESB 是輪輻式架構的進化版,它將整合邏輯分散到匯流排上,而非集中在單一樞紐中。它提供路由、轉換、協定中介和編排作為共享基礎架構服務。

  • 優點:處理複雜的整合場景(協定轉換、基於內容的路由、編排)。企業級的可靠性和監控。標準化工具讓非開發人員也能管理整合。
  • 缺點:顯著的基礎架構和授權成本。設置和維護複雜。如果管理不當,可能成為單體式瓶頸。通常被認為對現代架構來說過於笨重。
  • 適用時機:擁有跨多個系統和協定的多元整合需求的大型企業。擁有專門整合團隊的組織。

事件驅動架構 (EDA)

系統將事件(狀態變更的通知)發佈到共享的事件匯流排或 Message Broker。其他系統訂閱它們關心的事件並獨立回應。發佈者與訂閱者之間沒有直接耦合。

  • 優點:鬆散耦合——發佈者不知道也不在意誰在監聽。天然支援非同步處理。高度可擴展(新增訂閱者不影響發佈者)。實現即時資料流。
  • 缺點:最終一致性(訂閱者可能以不同速率處理事件)。更難除錯(沒有單一的請求/回應追蹤)。需要強健的事件基礎架構。必須處理事件排序和去重。
  • 適用時機:現代的微服務導向架構。當多個系統需要回應相同的業務事件時。當即時資料傳播很重要時。

EDI 標準與處理

電子資料交換 (EDI) 是組織之間使用標準化格式自動交換結構化商業文件。儘管已有數十年歷史,EDI 仍然是供應鏈作業的主要整合方法,尤其在零售、製造和物流領域。

EDI 標準

  • ANSI X12:北美洲的主要 EDI 標準。文件稱為 Transaction Sets,以數字識別——850(採購訂單)、810(發票)、856(預先出貨通知)、997(功能確認)。
  • UN/EDIFACT:國際標準,在歐洲和亞洲廣泛使用。文件稱為 Messages——ORDERS(採購訂單)、INVOIC(發票)、DESADV(發貨通知)。
  • XML-based EDI:現代替代方案如 cXML(commerce XML)、UBL(Universal Business Language)和 RosettaNet 使用 XML 取代傳統的固定格式區段。更容易解析和驗證,但在傳統供應鏈中的採用率較低。

iDempiere 中的 EDI 處理

iDempiere 不包含原生 EDI 引擎,但 Import/Export 框架為 EDI 處理提供了基礎。典型的 EDI 整合包括:

  1. 接收:傳入的 EDI 檔案透過 AS2、SFTP 或 VAN(加值網路)到達。EDI 轉換器(獨立工具如 Bots,或雲端服務如 SPS Commerce 或 TrueCommerce)將原始 EDI 格式轉換為結構化格式(CSV、XML、JSON)。
  2. 匯入 iDempiere:轉換後的資料透過 CSV 匯入或直接資料庫插入載入到 iDempiere 的匯入表(I_OrderI_InvoiceI_BPartner)。Import Loader 流程然後驗證並建立相應的商業文件。
  3. 從 iDempiere 匯出:外發文件(發票、預先出貨通知)透過 SQL 查詢或 API 呼叫從 iDempiere 中提取,由轉換器轉換為所需的 EDI 格式,並傳送給交易夥伴。

對於 EDI 量大的組織,考慮建置一個專用的 plugin 來自動化接收-轉換-匯入和匯出-轉換-傳送的工作流程,包括確認處理和錯誤通知。

訊息佇列整合

訊息佇列在系統之間提供非同步、可靠的通訊。它們在時間和可用性上將發送者與接收者解耦——即使接收者暫時離線,發送者也可以發佈訊息,而接收者則按照自己的節奏處理訊息。

Apache Kafka

Kafka 是一個分散式事件串流平台,專為高吞吐量和持久性而設計。訊息組織成 topics,消費者使用 consumer groups 從 topics 讀取。iDempiere 整合的關鍵特性:

  • 持久訊息儲存:Kafka 在磁碟上保留訊息一段可配置的時間(數天、數週或無限期),允許消費者在需要時重播事件。
  • 排序保證:partition 內的訊息嚴格排序。使用一致的 partition key(例如業務夥伴 ID、文件編號)來確保相關訊息按順序處理。
  • Consumer groups:同一消費者的多個實例可以共享處理 topic 的工作負載。Kafka 自動在群組成員之間平衡 partitions。
// Example: iDempiere plugin publishing order events to Kafka
Properties props = new Properties();
props.put("bootstrap.servers", "kafka-broker:9092");
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("acks", "all");  // Wait for all replicas to acknowledge

KafkaProducer<String, String> producer = new KafkaProducer<>(props);

// In a Model Validator after document completion
public String docValidate(PO po, int timing) {
    if (timing == TIMING_AFTER_COMPLETE && po instanceof MOrder) {
        MOrder order = (MOrder) po;
        String json = convertOrderToJson(order);
        ProducerRecord<String, String> record =
            new ProducerRecord<>("idempiere.orders",
                order.getDocumentNo(), json);
        producer.send(record);
    }
    return null;
}

RabbitMQ

RabbitMQ 是實作 AMQP(Advanced Message Queuing Protocol)標準的傳統 Message Broker。它擅長使用 exchanges 和 bindings 路由訊息,支援直接路由、基於主題的路由、扇出(廣播)和基於標頭的路由等模式。

  • 確認機制:消費者明確確認訊息處理。如果消費者在確認前終止,訊息會重新投遞給另一個消費者——保證至少一次投遞。
  • Dead letter exchanges:無法處理的訊息(過期、被拒絕或超過重試限制)會被路由到 dead letter exchange 進行調查。
  • 比 Kafka 更輕量:對於適中的訊息量,設置和操作更簡單。更適合傳統的請求-回覆模式和複雜路由規則。

非同步處理模式

將 iDempiere 與訊息佇列整合時,有幾種模式是必要的:

  • Command 模式:佇列訊息代表執行某個動作的指令(例如「建立此訂單」)。消費者驗證命令、執行命令,並發佈結果事件。
  • 事件通知模式:佇列訊息宣佈某事已發生(例如「訂單 12345 已完成」)。訂閱者獨立回應該事件。
  • 請求-回覆模式:發送者發佈帶有關聯 ID 和回覆佇列的請求訊息。消費者處理請求並將回應發佈到回覆佇列。原始發送者使用關聯 ID 來對應回應。

RESTful API 整合

REST API 是現代網路系統最常見的整合方法。iDempiere 透過社群 plugins 提供 REST API 功能,而且您將經常需要與外部 REST API 整合。

iDempiere 作為 API 提供者

iDempiere REST API plugin 將 iDempiere 的資料和操作作為 RESTful 端點公開。典型功能包括:

  • CRUD 操作:透過 HTTP 方法(POST、GET、PUT、DELETE)在任何 iDempiere 表中建立、讀取、更新和刪除記錄。
  • 流程執行:透過 API 呼叫觸發 iDempiere 流程,傳遞參數並接收結果。
  • 文件操作:透過 API 端點完成、作廢、沖銷和關閉文件。
  • 身分驗證:基於 Token 的身分驗證(通常是 JWT),並繼承 iDempiere 安全模型的角色存取控制。

iDempiere 作為 API 消費者

當 iDempiere 需要呼叫外部 API(例如取得運費費率、驗證稅務 ID、與市場同步庫存)時,使用 Java 的 HTTP 客戶端程式庫在 plugin 中實作整合:

// Example: Calling an external API from an iDempiere plugin
HttpClient client = HttpClient.newBuilder()
    .connectTimeout(Duration.ofSeconds(10))
    .build();

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.shipping.example/v2/rates"))
    .header("Authorization", "Bearer " + apiToken)
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(requestJson))
    .timeout(Duration.ofSeconds(30))
    .build();

HttpResponse<String> response = client.send(request,
    HttpResponse.BodyHandlers.ofString());

if (response.statusCode() == 200) {
    // Parse and process the response
    JSONObject rates = new JSONObject(response.body());
    // Update iDempiere records with the fetched rates
}

SOAP Web Services(舊版)

SOAP(Simple Object Access Protocol)Web Services 使用 XML 訊息傳遞,並透過 WSDL(Web Services Description Language)定義嚴格的合約。雖然 SOAP 已在大部分新整合中被 REST 取代,但在與舊版企業系統、政府入口網站和較舊的 ERP 系統整合時仍會遇到。

  • iDempiere 透過 org.adempiere.webservices bundle 提供舊版 SOAP Web Services 支援。
  • SOAP 服務提供更強的型別檢查、內建錯誤處理(SOAP faults)以及 WS-Security 企業身分驗證。
  • 在 iDempiere plugins 中使用 Java 的 JAX-WS 程式庫或 Apache CXF 來實作 SOAP 客戶端。

Webhook 模式

Webhook 反轉了輪詢模型:不是 iDempiere 定期檢查外部系統的變更,而是外部系統在事件發生時將通知推送到 iDempiere。在 iDempiere 中實作 Webhook 接收需要:

  1. 在 iDempiere 中註冊一個 servlet 或 REST 端點來接收傳入的 HTTP POST 請求。
  2. 簽章驗證(通常是 HMAC-SHA256)以確認 Webhook 來自預期的來源。
  3. 立即確認(回傳 HTTP 200),然後進行非同步處理以避免逾時問題。
  4. 冪等性處理——Webhook 可能會被投遞多次。

整合中的冪等性

在分散式系統中,由於網路重試、消費者重新啟動或 Message Broker 重新投遞,訊息可能被投遞多次。冪等性確保多次處理相同訊息與處理一次具有相同效果。

實作冪等性

  • 唯一訊息識別碼:在來源為每則訊息分配唯一 ID(UUID)。處理前,檢查是否已經處理過具有該 ID 的訊息。將已處理的訊息 ID 儲存在具有唯一約束的資料庫表中。
  • 自然業務鍵:使用現有的業務識別碼(外部訂單編號、發票號碼、出貨追蹤號碼)作為冪等性鍵。在建立新文件之前,檢查是否已存在具有該外部參考的文件。
  • 資料庫約束:依賴 iDempiere 表中的唯一索引作為安全網。例如,(AD_Client_ID, DocumentNo, C_DocType_ID) 上的唯一索引可防止重複建立文件。
// Idempotency check before processing an incoming order
String externalOrderId = incomingMessage.getExternalOrderId();

// Check if we already processed this order
String sql = "SELECT C_Order_ID FROM C_Order WHERE ExternalReference = ? AND AD_Client_ID = ?";
int existingOrderId = DB.getSQLValue(null, sql, externalOrderId, clientId);

if (existingOrderId > 0) {
    log.info("Order already exists for external ID " + externalOrderId + ", skipping");
    return; // Idempotent - no duplicate created
}

// Proceed with order creation
MOrder order = new MOrder(ctx, 0, null);
order.set_ValueOfColumn("ExternalReference", externalOrderId);
// ... populate order fields
order.saveEx();

錯誤處理與重試策略

整合錯誤是不可避免的。網路故障、服務中斷、資料驗證錯誤和速率限制都會發生。強健的錯誤處理策略是區分可靠整合與脆弱整合的關鍵。

分類錯誤

  • 暫時性錯誤:會自行解決的暫時性故障——網路逾時、HTTP 503(服務不可用)、資料庫連接池耗盡、速率限制(HTTP 429)。這些應該重試。
  • 永久性錯誤:沒有人為介入就不會解決的故障——無效資料(HTTP 400)、身分驗證失敗(HTTP 401)、找不到資源(HTTP 404)、業務規則違規。這些不應該重試,而應送到 dead letter queue 進行調查。

指數退避重試

對於暫時性錯誤,以遞增的延遲間隔重試操作:

// Exponential backoff retry pattern
int maxRetries = 5;
long baseDelay = 1000; // 1 second

for (int attempt = 0; attempt < maxRetries; attempt++) {
    try {
        executeIntegration();
        break; // Success
    } catch (TransientException e) {
        if (attempt == maxRetries - 1) throw e; // Final attempt failed
        long delay = baseDelay * (long) Math.pow(2, attempt);
        // Add jitter to prevent thundering herd
        delay += ThreadLocalRandom.current().nextLong(0, delay / 2);
        Thread.sleep(delay);
        log.warning("Retry attempt " + (attempt + 1) + " after " + delay + "ms");
    }
}

Dead Letter Queues

在所有重試嘗試後仍然處理失敗的訊息應該被路由到 dead letter queue (DLQ),而不是被靜默丟棄。DLQ 作為調查的暫存區域。在 DLQ 深度上實作監控和告警,並建置工具來檢查、修復和重播失敗的訊息。

斷路器模式

如果外部系統持續故障,繼續發送請求會浪費資源,並可能壓垮已經掙扎的系統。斷路器模式追蹤故障率,當故障超過閾值時「斷開」迴路(停止發送請求)。在冷卻期後,迴路進入「半開」狀態,允許單一測試請求通過。如果成功,迴路關閉(恢復正常操作);如果失敗,迴路再次斷開。

資料轉換與對應

資料很少在系統之間不經轉換就流動。iDempiere 使用特定的資料格式、欄位長度、參考值和慣例,這些可能與外部系統有顯著差異。

常見的轉換任務

  • 欄位對應:外部系統的欄位名稱和結構很少與 iDempiere 的匹配。維護明確的對應配置(JSON、XML 或資料庫表),而不是在程式碼中寫死對應關係。
  • 值轉換:將外部代碼值轉換為 iDempiere 的參考值(例如外部狀態碼轉換為 iDempiere 文件狀態,外部單位代碼轉換為 iDempiere UOM ID)。
  • 資料格式轉換:日期格式、數字格式、貨幣表示和地址結構在不同系統和地區之間各不相同。
  • 聚合與拆分:包含 100 個行項目的外部訂單可能需要根據倉庫或組織規則拆分為多個 iDempiere 訂單。相反地,多個外部事件可能需要聚合為單一 iDempiere 文件。

中介軟體平台

當整合複雜度超出您能以自訂程式碼合理管理的範圍時,中介軟體平台提供預建的連接器、視覺化對應工具和營運監控。

Apache Camel

Apache Camel 是一個實作企業整合模式 (EIP) 的開源整合框架。它提供領域特定語言 (DSL) 來定義端點之間的訊息路由。Camel 支援超過 300 個元件(連接器),適用於不同的系統和協定。

// Apache Camel route: File pickup, transform, and send to iDempiere
from("file:/edi/incoming?noop=true")
    .unmarshal().csv()
    .process(exchange -> {
        // Transform CSV to iDempiere import format
        List<List<String>> rows = exchange.getIn().getBody(List.class);
        String importData = transformToIdempiere(rows);
        exchange.getIn().setBody(importData);
    })
    .to("jdbc:idempiere?useHeadersAsParameters=true")
    .log("Imported ${header.CamelFileName} into iDempiere")
    .to("file:/edi/processed");

MuleSoft 和其他商業選項

MuleSoft Anypoint Platform、Dell Boomi、Microsoft Azure Integration Services 和 AWS Step Functions 提供基於雲端的整合平台,具有視覺化設計器、預建連接器和託管基礎架構。這些適合擁有多元整合環境和商業工具預算的大型企業。對於較小的部署,Apache Camel 或自訂 plugin 程式碼通常就足夠了。

實際範例:電子商務整合

讓我們逐步瞭解 iDempiere 與電子商務平台(如 WooCommerce、Shopify 或 Magento)之間完整整合的設計。此範例結合了本課中涵蓋的多種模式。

整合需求

  • 產品和庫存水準必須從 iDempiere 同步到電子商務平台。
  • 在電子商務平台上下的客戶訂單必須在 iDempiere 中建立為銷售訂單。
  • 來自 iDempiere 的出貨追蹤資訊必須推送回電子商務平台。
  • 客戶記錄必須雙向同步。

架構設計

使用事件驅動架構搭配訊息佇列(Kafka 或 RabbitMQ)作為整合骨幹:

  1. iDempiere Model Validators 在產品更新、庫存變更或出貨完成時將事件發佈到訊息佇列。
  2. 電子商務 webhooks 將新訂單和客戶事件推送到 webhook 接收器,再發佈到訊息佇列。
  3. 整合工作者(消費者流程)訂閱佇列 topics,在 iDempiere 和電子商務格式之間轉換資料,並呼叫適當的 API 來同步資料。
  4. 錯誤處理:失敗的訊息進入 dead letter queues 並發出告警。重試排程器定期嘗試重新處理失敗的訊息。

資料對應考量

  • 將電子商務產品 SKU 對應到 iDempiere 的 M_Product.Value(Search Key)。
  • 將電子商務客戶電子郵件地址對應到 iDempiere 的 C_BPartner 記錄,為首次購買的客戶建立新的業務夥伴。
  • 將電子商務訂單狀態對應到 iDempiere 文件動作(草稿、完成、作廢)。
  • 處理計量單位轉換、貨幣轉換以及系統之間的稅務計算差異。
  • 將外部系統 ID 儲存在 iDempiere 自訂欄位中(例如 ShopifyOrderID),用於交叉參考和冪等性。

庫存同步細節

庫存同步需要特別注意,因為庫存水準頻繁變動,錯誤直接影響客戶體驗(超賣或低賣):

  1. iDempiere Model Validator 在 M_Transaction(記錄每次庫存移動的表)儲存後觸發。
  2. 驗證器使用 MStorageOnHand 計算受影響的產品-倉庫組合的新可用數量。
  3. 它將庫存更新事件發佈到訊息佇列,包含產品 SKU、倉庫和新數量。
  4. 整合工作者消費該事件並呼叫電子商務平台的 API 來更新庫存水準。
  5. 為了處理快速連續的庫存變更,工作者批次處理更新(例如每 30 秒只發送每個 SKU 的最新數量)以避免 API 速率限制。

總結

整合是 iDempiere 與更廣泛的企業生態系統交會之處。您選擇的模式——點對點 vs. 事件驅動、同步 vs. 非同步、輪詢 vs. webhook——應該由您對可靠性、延遲、量和營運複雜度的具體需求來驅動。需要記住的關鍵原則是:

  • 為故障而設計——每個整合都會遇到錯誤,因此從一開始就建置重試、dead letter queues 和斷路器。
  • 確保冪等性——在分散式系統中,重複訊息是不可避免的。
  • 優先選擇非同步模式以獲得更好的可擴展性和彈性。
  • 從簡單開始(點對點),隨著複雜度的需求演進到更複雜的模式(事件驅動、中介軟體)。
  • 徹底記錄您的資料對應——它們是整合錯誤最常見的來源。

在下一課中,我們將專注於身分驗證和單一登入——如何使用 LDAP、OAuth2、SAML 和自訂身分驗證提供者來保護您的 iDempiere 部署。

日本語

概要

  • 学習内容:
    • ポイントツーポイント、ハブアンドスポーク、ESB、イベント駆動型アプローチなどの統合アーキテクチャパターンを使用して、iDempiere を外部システムと接続する方法
    • 信頼性の高いシステム間通信を実現するために、EDI 処理、メッセージキュー統合、RESTful API パターンを実装する方法
    • 統合ワークフローにおけるエラー処理、リトライ、べき等性の扱い方(実践的な EC 統合の例を含む)
  • 前提条件:レッスン 40 — システムアーキテクチャ設計、REST API およびメッセージングの概念に精通していること
  • 推定読了時間:25 分

はじめに

ERP システムは単独では稼働しません。現代の企業において、iDempiere は EC プラットフォーム、CRM システム、倉庫管理システム、決済ゲートウェイ、銀行インターフェース、政府税務ポータル、その他無数のアプリケーションとデータを交換する必要があります。これらの統合をどのように設計するか——選択するパターン、実装するエラー処理、管理するデータ変換——によって、統合が信頼性が高く保守しやすいものになるか、脆弱で予測不能なものになるかが決まります。

本レッスンでは、iDempiere を外部システムに接続する際に遭遇する基本的な統合パターンと技術を扱います。アーキテクチャ理論から実装へと進み、iDempiere と EC プラットフォームを統合する実践例で締めくくります。

統合アーキテクチャパターン

特定の技術に踏み込む前に、システム間の通信を統制するアーキテクチャパターンを理解することが重要です。正しいパターンを選ぶことが、その後のすべてに影響します。

ポイントツーポイント統合

各システムは、通信する必要のある他のすべてのシステムに直接接続します。システム A がシステム B と通信し、システム B がシステム C と通信する、という具合です。

  • 利点:少数の接続であれば最も実装が簡単。ミドルウェアインフラストラクチャが不要。低レイテンシ(直接通信)。
  • 欠点:接続数は指数的に増加——N 個のシステムで最大 N(N-1)/2 の接続が必要。システム間が密結合になる。1 つのシステムの API 変更により、接続されているすべてのシステムの更新が必要。4〜5 個以上の統合システムでは管理不能になる。
  • 使用すべき場面:統合するシステムが 2〜3 個のみで、統合要件がシンプルで変更の可能性が低い場合。

ハブアンドスポーク(Message Broker)

中央ハブがシステム間のメッセージをルーティングします。各システムはハブにのみ接続し、他のすべてのシステムには接続しません。ハブがメッセージのルーティング、変換、配信を処理します。

  • 利点:接続の複雑さを N 個の接続(システムごとに 1 つ)に削減。メッセージのルーティングと変換ロジックを一元化。新しいシステムの追加が容易——ハブに接続するだけ。
  • 欠点:ハブが単一障害点になる(高可用性にする必要がある)。すべてのトラフィックがハブを通るため、ボトルネックになり得る。ハブ固有の知識が必要。
  • 使用すべき場面:5〜15 個のシステムを含む中程度の複雑さの統合環境。一元的なメッセージ変換とルーティングが必要な場合。

Enterprise Service Bus (ESB)

ハブアンドスポークの進化版である ESB は、統合ロジックを単一のハブに集中させるのではなく、バス全体に分散させます。ルーティング、変換、プロトコル仲介、オーケストレーションを共有インフラストラクチャサービスとして提供します。

  • 利点:複雑な統合シナリオ(プロトコル変換、コンテンツベースルーティング、オーケストレーション)に対応。エンタープライズグレードの信頼性と監視。非開発者が統合を管理するための標準ツール。
  • 欠点:インフラストラクチャとライセンスに大きなコスト。セットアップと保守が複雑。慎重に管理しないとモノリシックなボトルネックになり得る。現代のアーキテクチャには重量級と見なされることが多い。
  • 使用すべき場面:多くのシステムとプロトコルにまたがる多様な統合要件を持つ大企業。専門の統合チームを持つ組織。

イベント駆動型アーキテクチャ (EDA)

システムは、共有イベントバスまたは Message Broker にイベント(状態変更の通知)を発行します。他のシステムは関心のあるイベントを購読し、独立して反応します。パブリッシャーとサブスクライバー間に直接的な結合はありません。

  • 利点:疎結合——パブリッシャーは誰がリスニングしているか知る必要も気にする必要もない。非同期処理を自然にサポート。高いスケーラビリティ(パブリッシャーに影響なくサブスクライバーを追加可能)。リアルタイムデータフローを実現。
  • 欠点:結果整合性(サブスクライバーが異なる速度でイベントを処理する可能性がある)。デバッグが困難(単一のリクエスト/レスポンストレースがない)。堅牢なイベントインフラストラクチャが必要。イベントの順序付けと重複排除を処理する必要がある。
  • 使用すべき場面:現代のマイクロサービス志向アーキテクチャ。複数のシステムが同じビジネスイベントに反応する必要がある場合。リアルタイムのデータ伝播が重要な場合。

EDI 標準と処理

電子データ交換(EDI)は、標準化されたフォーマットを使用した組織間の構造化ビジネス文書の自動交換です。数十年の歴史がありますが、EDI は依然としてサプライチェーンオペレーションの主要な統合方法であり、特に小売、製造、物流分野で使われています。

EDI 標準

  • ANSI X12:北米の主要な EDI 標準。文書は Transaction Sets と呼ばれ、番号で識別されます——850(購買発注書)、810(請求書)、856(事前出荷通知)、997(機能確認)。
  • UN/EDIFACT:国際標準で、ヨーロッパとアジアで広く使用されています。文書は Messages と呼ばれます——ORDERS(購買発注書)、INVOIC(請求書)、DESADV(出荷通知)。
  • XML ベースの EDI:cXML(commerce XML)、UBL(Universal Business Language)、RosettaNet などの現代的な代替手段は、従来の固定フォーマットセグメントの代わりに XML を使用します。解析と検証が容易ですが、レガシーサプライチェーンでの普及率は低いです。

iDempiere における EDI 処理

iDempiere にはネイティブ EDI エンジンは含まれていませんが、Import/Export フレームワークが EDI 処理の基盤を提供します。典型的な EDI 統合には以下が含まれます:

  1. 受信:受信 EDI ファイルは AS2、SFTP、または VAN(Value-Added Network)経由で到着します。EDI トランスレータ(Bots のようなスタンドアロンツール、または SPS Commerce や TrueCommerce のようなクラウドサービス)が、生の EDI フォーマットを構造化フォーマット(CSV、XML、JSON)に変換します。
  2. iDempiere へのインポート:変換されたデータは、CSV インポートまたは直接データベース挿入により、iDempiere のインポートテーブル(I_OrderI_InvoiceI_BPartner)にロードされます。Import Loader プロセスがデータを検証し、対応するビジネス文書を作成します。
  3. iDempiere からのエクスポート:送信文書(請求書、事前出荷通知)は SQL クエリまたは API コールにより iDempiere から抽出され、トランスレータによって必要な EDI フォーマットに変換され、取引先に送信されます。

EDI 処理量が多い組織では、受信-変換-インポートおよびエクスポート-変換-送信のワークフロー(確認処理やエラー通知を含む)を自動化する専用プラグインの構築を検討してください。

メッセージキュー統合

メッセージキューは、システム間の非同期で信頼性の高い通信を提供します。送信者と受信者を時間と可用性の両面で分離します——受信者が一時的にオフラインであっても送信者はメッセージを発行でき、受信者は自分のペースでメッセージを処理します。

Apache Kafka

Kafka は、高スループットと耐久性のために設計された分散イベントストリーミングプラットフォームです。メッセージは topics に整理され、コンシューマーは consumer groups を使用して topics から読み取ります。iDempiere 統合の主要な特性:

  • 永続メッセージストレージ:Kafka は設定可能な期間(数日、数週間、または無期限)メッセージをディスクに保持し、必要に応じてコンシューマーがイベントをリプレイできます。
  • 順序保証:partition 内のメッセージは厳密に順序付けられます。一貫した partition key(例:ビジネスパートナー ID、文書番号)を使用して、関連メッセージが順序通りに処理されるようにします。
  • Consumer groups:同じコンシューマーの複数のインスタンスが topic の処理ワークロードを共有できます。Kafka がグループメンバー間で partition を自動的にバランスします。
// Example: iDempiere plugin publishing order events to Kafka
Properties props = new Properties();
props.put("bootstrap.servers", "kafka-broker:9092");
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("acks", "all");  // Wait for all replicas to acknowledge

KafkaProducer<String, String> producer = new KafkaProducer<>(props);

// In a Model Validator after document completion
public String docValidate(PO po, int timing) {
    if (timing == TIMING_AFTER_COMPLETE && po instanceof MOrder) {
        MOrder order = (MOrder) po;
        String json = convertOrderToJson(order);
        ProducerRecord<String, String> record =
            new ProducerRecord<>("idempiere.orders",
                order.getDocumentNo(), json);
        producer.send(record);
    }
    return null;
}

RabbitMQ

RabbitMQ は、AMQP(Advanced Message Queuing Protocol)標準を実装する伝統的な Message Broker です。exchanges と bindings を使用したメッセージルーティングに優れ、ダイレクトルーティング、トピックベースルーティング、ファンアウト(ブロードキャスト)、ヘッダーベースルーティングなどのパターンをサポートします。

  • 確認応答:コンシューマーはメッセージ処理を明示的に確認します。確認前にコンシューマーが終了した場合、メッセージは別のコンシューマーに再配信されます——少なくとも 1 回の配信を保証します。
  • Dead letter exchanges:処理できないメッセージ(期限切れ、拒否、またはリトライ上限超過)は、調査のために dead letter exchange にルーティングされます。
  • Kafka より軽量:中程度のメッセージ量であれば、セットアップと運用が簡単。従来のリクエスト-リプライパターンや複雑なルーティングルールにより適しています。

非同期処理パターン

iDempiere をメッセージキューと統合する際、いくつかのパターンが不可欠です:

  • Command パターン:キューメッセージはアクションを実行するための指示を表します(例:「この注文を作成する」)。コンシューマーがコマンドを検証・実行し、結果イベントを発行します。
  • イベント通知パターン:キューメッセージは何かが起きたことを通知します(例:「注文 12345 が完了しました」)。サブスクライバーはそのイベントに独立して反応します。
  • リクエスト-リプライパターン:送信者が相関 ID とリプライキューを含むリクエストメッセージを発行します。コンシューマーがリクエストを処理し、リプライキューにレスポンスを発行します。元の送信者が相関 ID を使用してレスポンスを対応付けます。

RESTful API 統合

REST API は、現代の Web ベースシステムで最も一般的な統合方法です。iDempiere はコミュニティプラグインを通じて REST API 機能を提供しており、外部 REST API との統合も頻繁に必要になります。

API プロバイダーとしての iDempiere

iDempiere REST API プラグインは、iDempiere のデータと操作を RESTful エンドポイントとして公開します。典型的な機能には以下が含まれます:

  • CRUD 操作:HTTP メソッド(POST、GET、PUT、DELETE)を使用して、任意の iDempiere テーブルのレコードを作成、読み取り、更新、削除。
  • プロセス実行:API コールを通じて iDempiere プロセスをトリガーし、パラメータを渡して結果を受け取る。
  • 文書操作:API エンドポイントを通じて文書の完了、無効化、取消、クローズを実行。
  • 認証:トークンベースの認証(通常は JWT)で、iDempiere のセキュリティモデルから継承されたロールベースのアクセス制御。

API コンシューマーとしての iDempiere

iDempiere が外部 API を呼び出す必要がある場合(例:配送料金の取得、税務 ID の検証、マーケットプレイスとの在庫同期)、Java の HTTP クライアントライブラリを使用してプラグインに統合を実装します:

// Example: Calling an external API from an iDempiere plugin
HttpClient client = HttpClient.newBuilder()
    .connectTimeout(Duration.ofSeconds(10))
    .build();

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.shipping.example/v2/rates"))
    .header("Authorization", "Bearer " + apiToken)
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(requestJson))
    .timeout(Duration.ofSeconds(30))
    .build();

HttpResponse<String> response = client.send(request,
    HttpResponse.BodyHandlers.ofString());

if (response.statusCode() == 200) {
    // Parse and process the response
    JSONObject rates = new JSONObject(response.body());
    // Update iDempiere records with the fetched rates
}

SOAP Web Services(レガシー)

SOAP(Simple Object Access Protocol)Web Services は、WSDL(Web Services Description Language)で定義された厳格な契約に基づく XML メッセージングを使用します。新しい統合では SOAP はほぼ REST に置き換えられましたが、レガシーエンタープライズシステム、政府ポータル、古い ERP システムとの統合では依然として遭遇します。

  • iDempiere は org.adempiere.webservices バンドルを通じてレガシー SOAP Web Services サポートを提供しています。
  • SOAP サービスは、より強力な型付け、組み込みエラー処理(SOAP faults)、WS-Security によるエンタープライズ認証を提供します。
  • iDempiere プラグインでの SOAP クライアント実装には、Java の JAX-WS ライブラリまたは Apache CXF を使用します。

Webhook パターン

Webhook はポーリングモデルを反転させます:iDempiere が外部システムの変更を定期的にチェックする代わりに、イベントが発生した時に外部システムが iDempiere に通知をプッシュします。iDempiere で Webhook の受信を実装するには以下が必要です:

  1. 受信 HTTP POST リクエストを受け取るために iDempiere に登録された servlet または REST エンドポイント。
  2. Webhook が予期されたソースからのものであることを確認する署名検証(通常は HMAC-SHA256)。
  3. タイムアウトの問題を避けるための即時確認応答(HTTP 200 を返す)とその後の非同期処理。
  4. べき等性の処理——Webhook は複数回配信される可能性がある。

統合におけるべき等性

分散システムでは、ネットワークリトライ、コンシューマーの再起動、または Message Broker の再配信により、メッセージが複数回配信される可能性があります。べき等性は、同じメッセージを複数回処理しても 1 回処理したのと同じ効果であることを保証します。

べき等性の実装

  • 一意のメッセージ識別子:ソースで各メッセージに一意の ID(UUID)を割り当てます。処理前に、その ID のメッセージが既に処理されたかどうかを確認します。処理済みメッセージ ID をユニーク制約のあるデータベーステーブルに保存します。
  • 自然ビジネスキー:既存のビジネス識別子(外部注文番号、請求書番号、出荷追跡番号)をべき等性キーとして使用します。新しい文書を作成する前に、その外部参照を持つ文書が既に存在するかどうかを確認します。
  • データベース制約:安全策として iDempiere テーブルのユニークインデックスに依存します。例えば、(AD_Client_ID, DocumentNo, C_DocType_ID) のユニークインデックスは文書の重複作成を防止します。
// Idempotency check before processing an incoming order
String externalOrderId = incomingMessage.getExternalOrderId();

// Check if we already processed this order
String sql = "SELECT C_Order_ID FROM C_Order WHERE ExternalReference = ? AND AD_Client_ID = ?";
int existingOrderId = DB.getSQLValue(null, sql, externalOrderId, clientId);

if (existingOrderId > 0) {
    log.info("Order already exists for external ID " + externalOrderId + ", skipping");
    return; // Idempotent - no duplicate created
}

// Proceed with order creation
MOrder order = new MOrder(ctx, 0, null);
order.set_ValueOfColumn("ExternalReference", externalOrderId);
// ... populate order fields
order.saveEx();

エラー処理とリトライ戦略

統合エラーは避けられません。ネットワーク障害、サービス停止、データ検証エラー、レート制限はすべて発生します。堅牢なエラー処理戦略が、信頼性の高い統合と脆弱な統合を区別します。

エラーの分類

  • 一時的なエラー:自然に解決する一時的な障害——ネットワークタイムアウト、HTTP 503(Service Unavailable)、データベース接続プール枯渇、レート制限(HTTP 429)。これらはリトライすべきです。
  • 永続的なエラー:介入なしには解決しない障害——無効なデータ(HTTP 400)、認証失敗(HTTP 401)、リソース未検出(HTTP 404)、ビジネスルール違反。これらはリトライせず、調査のために dead letter queue に送るべきです。

指数バックオフによるリトライ

一時的なエラーに対しては、試行間の遅延を増加させながら操作をリトライします:

// Exponential backoff retry pattern
int maxRetries = 5;
long baseDelay = 1000; // 1 second

for (int attempt = 0; attempt < maxRetries; attempt++) {
    try {
        executeIntegration();
        break; // Success
    } catch (TransientException e) {
        if (attempt == maxRetries - 1) throw e; // Final attempt failed
        long delay = baseDelay * (long) Math.pow(2, attempt);
        // Add jitter to prevent thundering herd
        delay += ThreadLocalRandom.current().nextLong(0, delay / 2);
        Thread.sleep(delay);
        log.warning("Retry attempt " + (attempt + 1) + " after " + delay + "ms");
    }
}

Dead Letter Queues

すべてのリトライ試行後も処理に失敗したメッセージは、暗黙的に破棄するのではなく、dead letter queue (DLQ) にルーティングすべきです。DLQ は調査のための保持領域として機能します。DLQ の深さに対する監視とアラートを実装し、失敗したメッセージを検査、修正、リプレイするためのツールを構築してください。

サーキットブレーカーパターン

外部システムが継続的に障害を起こしている場合、リクエストを送り続けるとリソースが浪費され、苦戦しているシステムに過大な負荷をかける可能性があります。サーキットブレーカーパターンは障害率を追跡し、障害がしきい値を超えた時に回路を「オープン」(リクエストの送信を停止)します。クールダウン期間の後、回路は「ハーフオープン」状態に入り、単一のテストリクエストの通過を許可します。成功すれば回路がクローズ(通常運用再開)し、失敗すれば回路は再びオープンします。

データ変換とマッピング

データが変換なしにシステム間を流れることはほとんどありません。iDempiere は、外部システムとは大きく異なる可能性のある特定のデータフォーマット、フィールド長、参照値、規約を使用しています。

一般的な変換タスク

  • フィールドマッピング:外部システムのフィールド名と構造は、iDempiere のものと一致することはほとんどありません。コードにマッピングをハードコードするのではなく、明示的なマッピング構成(JSON、XML、またはデータベーステーブル)を維持してください。
  • 値変換:外部コード値を iDempiere の参照値に変換します(例:外部ステータスコードを iDempiere 文書ステータスに、外部単位コードを iDempiere UOM ID に)。
  • データフォーマット変換:日付フォーマット、数値フォーマット、通貨表現、住所構造はシステムや地域によって異なります。
  • 集約と分割:100 行項目を持つ外部注文は、倉庫や組織のルールに基づいて複数の iDempiere 注文に分割が必要な場合があります。逆に、複数の外部イベントを単一の iDempiere 文書に集約する必要がある場合もあります。

ミドルウェアプラットフォーム

統合の複雑さがカスタムコードで合理的に管理できる範囲を超えた場合、ミドルウェアプラットフォームが事前構築されたコネクタ、ビジュアルマッピングツール、運用監視を提供します。

Apache Camel

Apache Camel は、Enterprise Integration Patterns (EIP) を実装するオープンソース統合フレームワークです。エンドポイント間のメッセージルートを定義するためのドメイン固有言語 (DSL) を提供します。Camel は 300 以上のコンポーネント(コネクタ)をサポートし、さまざまなシステムとプロトコルに対応します。

// Apache Camel route: File pickup, transform, and send to iDempiere
from("file:/edi/incoming?noop=true")
    .unmarshal().csv()
    .process(exchange -> {
        // Transform CSV to iDempiere import format
        List<List<String>> rows = exchange.getIn().getBody(List.class);
        String importData = transformToIdempiere(rows);
        exchange.getIn().setBody(importData);
    })
    .to("jdbc:idempiere?useHeadersAsParameters=true")
    .log("Imported ${header.CamelFileName} into iDempiere")
    .to("file:/edi/processed");

MuleSoft およびその他の商用オプション

MuleSoft Anypoint Platform、Dell Boomi、Microsoft Azure Integration Services、AWS Step Functions は、ビジュアルデザイナー、事前構築されたコネクタ、マネージドインフラストラクチャを備えたクラウドベースの統合プラットフォームを提供します。これらは、多様な統合環境と商用ツールの予算を持つ大企業に適しています。小規模なデプロイメントでは、通常 Apache Camel またはカスタムプラグインコードで十分です。

実践例:EC 統合

iDempiere と EC プラットフォーム(WooCommerce、Shopify、Magento など)間の完全な統合設計を順を追って見ていきましょう。この例は、本レッスンで扱った複数のパターンを組み合わせています。

統合要件

  • 製品と在庫レベルを iDempiere から EC プラットフォームに同期する必要がある。
  • EC プラットフォームで注文された顧客注文を iDempiere で販売注文として作成する必要がある。
  • iDempiere からの出荷追跡情報を EC プラットフォームにプッシュバックする必要がある。
  • 顧客レコードを双方向に同期する必要がある。

アーキテクチャ設計

メッセージキュー(Kafka または RabbitMQ)を統合バックボーンとしたイベント駆動型アーキテクチャを使用します:

  1. iDempiere Model Validators が、製品の更新、在庫変更、出荷完了時にメッセージキューにイベントを発行します。
  2. EC の webhooks が、新しい注文や顧客イベントを webhook レシーバーにプッシュし、メッセージキューに発行します。
  3. 統合ワーカー(コンシューマープロセス)がキューの topics を購読し、iDempiere と EC フォーマット間でデータを変換し、適切な API を呼び出してデータを同期します。
  4. エラー処理:失敗したメッセージは dead letter queues に送られ、アラートが発行されます。リトライスケジューラが定期的に失敗したメッセージの再処理を試みます。

データマッピングの考慮事項

  • EC の製品 SKU を iDempiere の M_Product.Value(Search Key)にマッピング。
  • EC の顧客メールアドレスを iDempiere の C_BPartner レコードにマッピングし、初回購入の顧客には新しいビジネスパートナーを作成。
  • EC の注文ステータスを iDempiere の文書アクション(ドラフト、完了、無効化)にマッピング。
  • 計量単位の変換、通貨変換、システム間の税計算の差異を処理。
  • 外部システム ID を iDempiere のカスタムカラム(例:ShopifyOrderID)に保存し、相互参照とべき等性に使用。

在庫同期の詳細

在庫同期には特に注意が必要です。在庫レベルは頻繁に変動し、エラーは顧客体験に直接影響します(過剰販売や過少販売):

  1. iDempiere Model Validator が M_Transaction(すべての在庫移動を記録するテーブル)の保存後に起動します。
  2. バリデーターが MStorageOnHand を使用して、影響を受けた製品-倉庫の組み合わせの新しい利用可能数量を計算します。
  3. 製品 SKU、倉庫、新しい数量を含む在庫更新イベントをメッセージキューに発行します。
  4. 統合ワーカーがイベントを消費し、EC プラットフォームの API を呼び出して在庫レベルを更新します。
  5. 急速に連続する在庫変更に対応するため、ワーカーは更新をバッチ処理(例:各 SKU の最新数量を 30 秒ごとにのみ送信)し、API レート制限を回避します。

まとめ

統合は、iDempiere がより広いエンタープライズエコシステムと出会う場所です。選択するパターン——ポイントツーポイント vs. イベント駆動、同期 vs. 非同期、ポーリング vs. webhook——は、信頼性、レイテンシ、ボリューム、運用の複雑さに対する具体的な要件に基づいて決定すべきです。覚えておくべき主要な原則は:

  • 障害に備えて設計する——すべての統合はエラーを経験するため、最初からリトライ、dead letter queues、サーキットブレーカーを組み込む。
  • べき等性を確保する——分散システムでは重複メッセージは避けられない。
  • より良いスケーラビリティと回復力のために非同期パターンを優先する。
  • シンプルに始め(ポイントツーポイント)、複雑さの要求に応じてより高度なパターン(イベント駆動、ミドルウェア)に進化させる。
  • データマッピングを徹底的に文書化する——統合バグの最も一般的な原因です。

次のレッスンでは、認証とシングルサインオンに焦点を当てます——LDAP、OAuth2、SAML、カスタム認証プロバイダーを使用して iDempiere デプロイメントを保護する方法です。

You Missed