EDI
Basic Principles
Integration with EDI providers is built on the standard mechanism for the integrations microservice - synchronizations. This means we have a simple way to manage the integration state with a specific EDI provider within a configured box in ECOS using ready-made functionality (enabling/disabling with checkboxes, resetting the state if necessary to start integration from the beginning, etc.).
Let’s proceed to describe the functionality itself with class references.
Citeck synchronizations work on the mechanism of declaring SyncExecutionFactory implementations, which supply SyncExecution implementations where the integration scheduling actually occurs.
In our case, the classes responsible for this are EdiSyncExecutionFactory and EdiSyncExecution. We won’t examine the work of EdiSyncExecutionFactory since it does nothing besides registering in SyncService and creating EdiSyncExecution.
Let’s examine the work of EdiSyncExecution:
Schedule a job according to the settings.
In the job - acquire a lock using ShedLock. If the lock is acquired successfully - work continues.
Collects data for integration, searches for a registered implementation of the EdiEventsSyncService interface for the EDI provider from the box settings. If not found, throws exceptions. It’s important to note that implementations of EdiEventsSyncService do not actually exist in the integrations microservice itself; how they are connected will be described in the section below.
Delegates work to the found EdiEventsSyncService, passing it the previously collected data + a callback method for updating the synchronization state.
That is, in fact, EdiSyncExecution doesn’t do much specific work; the useful work is performed through delegation.
Connection of implementation services with EdiSyncExecution for integration
The answer is quite simple: there is a common library ecos-edi-commons, which contains the main integration interfaces and data structures. This way, the solution is linked at the interface level (meaning the interface is used in the integrations microservice, while the implementation resides in external libraries).
Okay, understood that part; something is implemented, but how will the microservice get it if it doesn’t even have these dependencies? The answer here is more complex. The solution is based on loading library code into the microservice as OSGi bundles. For a more detailed study of this, you can read the article OSGI package loading functionality (and recommended articles), as well as the example of loading the Kontur library for this purpose - Setting up event reception from the Kontur_Diadoc box
Let’s examine which specific interfaces and services are defined in the ecos-edi-commons library:
EdiEventsSyncService - the interface to which all integration with the EDI provider is delegated.
EdiEventsSyncServiceResolver - a class where EdiEventsSyncService implementations are registered by the “EDI-Provider - Service” pair when a bundle intended for integration with a specific EDI provider is loaded. Contained in the microservice as a bean.
EdiBoxService - an interface for obtaining information about a box. Extended in the main code of the microservice as a bean.
EdiApiService - an interface for communicating with the EDI provider. Contains methods for all EDI operations (or almost all).
EdiApiServiceResolver - a class where EdiApiService implementations are registered by the “EDI-Provider - Service” pair when a bundle intended for integration with a specific EDI provider is loaded. Contained in the microservice as a bean.
EdiService - A class that contains the same methods as EdiApiService, except that each method additionally takes an EdiProviderType parameter. Essentially, it is a composite EdiApiService. Delegates logic to a specific EdiApiService, obtained by the EdiProviderType pair from EdiApiServiceResolver.
EdiGenerator + child interfaces - interfaces for extending content generation capabilities in EDI providers. For example, there could be 2 implementations for generating a printed form: via API call for PF generation in Diadoc services (remote generation) or generation by ECOS itself (local). Registered in EdiGeneratorResolver.
EdiGeneratorResolver - a class for registering EdiGenerator implementations by a composite key “EDI-provider+Generator-Type+Generator-Kind”, where EDI-provider is Kontur or Korus, Generator-Type is Print Form Generation or Buyer Title Generation, Generator-Kind is an arbitrary string symbolizing the kind. Usually something like “local generation” or “API generation”.
EdiStateService - A service for sending events for processing after receiving and initial processing in the library (will be discussed below).
Approximate service interaction can be studied in more detail in the drawIO diagram:
What happens in the processing libraries and what is EdiStateService
The libraries do not process events. They receive events based on the last processed event (stored in the synchronization state), create a universal Event structure stored in the ecos-edi-commons library, and then send this structure to EdiStateService.
The structures in ecos-edi-commons can be viewed in the following drawIO diagram:
EdiStateService is a class in ecos-edi-commons that sends events to a specific endpoint within a camel context. The sender’s CamelContext and the receiver’s CamelContext are typically different contexts. This kind of transfer is achieved by using a direct-vm type endpoint, not a simple direct one.
Thus, the following interaction occurs:
, where the steps are indicated:
1 - A request is sent to perform integration via Kontur (or another EDI provider option), for a specific box, from a specific event (call to EdiEventsSyncService).
2 - If events are found - transforms them into the Event structure and via EdiStateService sends a message to Camel from the Camel context of the integrations microservice.
3 - The Camel context of the integrations microservice sends the message with the Event to a CamelContext inside the VM where the specified endpoint is registered. The screenshot indicates that we also use some customer-lib with its own camel context, but such customization is not always needed; in the general case, it will transition directly to ecos-lib.
4 - After performing some work in the customer-lib routes - they send a message to the CamelContext of the ecos-lib library. There, documents, signatures, etc., are updated in Alfresco via Records API calls.
It’s worth clarifying again: customer-lib and ecos-lib are separate OSGi bundles included in the microservice after its start, which create and start a Camel context, on whose routes the connection between them is established. The endpoint naming contract must be strictly followed.
Event Structure
Event - обычный POJO, с сеттерами, геттерами, equals и тд. Однако, заполнение Event носит определенный характер. Внутри него ДОЛЖНЫ содержаться все документы, состояния которых изменены в рамках данного события.
Это означает, что если обрабатываем событие “Документ подписан”, то это означает, что должна прийти не просто подпись, а еще и информация о документе с АКТУАЛЬНЫМ статусом.
Not exactly. No, I don’t mean that Event is some tricky structure. It’s a regular POJO, with setters, getters, equals, etc. However, populating the Event has a specific nature. It MUST contain all documents whose states have changed within this event. This means that if we are processing a “Document signed” event, it should include not just the signature, but also information about the document with its CURRENT status. Another situation: if a correction (UKD) comes for a document like UPD (Universal Transfer Document), this means that within this event, not only the UKD will arrive, but also information about the current new state of the UPD (status only). Unchanged fields, such as content or content-based formalized attributes that might be heavy to transport, are omitted.”# SOME DESCRIPTIVE TITLE