How phase4 detects and rejects duplicate incoming AS4 messages.
phase4 includes built-in duplicate message detection to protect against accidentally processing the same AS4 message more than once. This is a key reliability feature when combined with retries.
When an incoming user message is processed, phase4 calls IAS4DuplicateManager.registerAndCheck(...) with the message ID. If the message ID has already been registered, the manager returns EContinue.BREAK and the message is rejected with an AS4 error. Otherwise it is registered and processing continues normally.
Incoming message ↓registerAndCheck(messageID, profileID, pmodeID) ├─ New ID → Register + CONTINUE processing └─ Known ID → BREAK → Return AS4 duplicate error
public interface IAS4DuplicateManager { // Check and register a message ID. // Returns CONTINUE if new, BREAK if duplicate. @NonNull EContinue registerAndCheck( @Nullable String sMessageID, @Nullable String sProfileID, @Nullable String sPModeID ); // Find a registered item by message ID @Nullable IAS4DuplicateItem getItemOfMessageID(@Nullable String sMessageID); // Get all registered items @NonNull ICommonsList<IAS4DuplicateItem> getAll(); // Evict all items received before the given date/time @NonNull ICommonsList<String> evictAllItemsBefore(@NonNull OffsetDateTime aRefDT); // Clear the entire cache @NonNull EChange clearCache();}
import com.helger.phase4.duplicate.AS4DuplicateManagerInMemory;// The default manager used when no custom one is configuredAS4DuplicateManagerInMemory dupMgr = new AS4DuplicateManagerInMemory();// Register and check a message IDEContinue result = dupMgr.registerAndCheck("msg-id-12345", "peppol", "pmode-id");if (result.isBreak()) { // Message is a duplicate}
import com.helger.phase4.duplicate.AS4DuplicateManagerXML;// Persists to a file under the configured data pathAS4DuplicateManagerXML dupMgr = new AS4DuplicateManagerXML( new File("/data/phase4/duplicates"));
To replace the default implementation (e.g. with a database-backed store), implement IAS4DuplicateManager and register it:
import com.helger.phase4.mgr.MetaAS4Manager;// Replace the global duplicate managerMetaAS4Manager.getDuplicateMgr(); // get current// Registration depends on how the manager is initialised at startup// (see MetaAS4Manager documentation)
With AS4DuplicateManagerInMemory, all registered message IDs are lost on server restart. If your system needs to handle retries that may arrive after a restart, use AS4DuplicateManagerXML or a custom persistent implementation.
Message IDs are stored without any normalisation. The comparison is an exact string match against the EBMS3 MessageId header value.