Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 16 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ public class IncomingMessageHandler implements UftpIncomingHandler<FlexRequest>
}

@Override
public void handle(UftpParticipant sender, FlexRequest message) {
public void handle(IncomingUftpMessage<FlexRequest> message) {
// call UftpReceivedMessageService immediately or queue for later processing
}
}
Expand All @@ -222,7 +222,7 @@ To process a message (asynchronously) you can use the `UftpReceivedMessageServic
@Autowired
UftpReceivedMessageService uftpReceivedMessageService;

uftpReceivedMessageService.process(sender,message);
uftpReceivedMessageService.process(message);
```

To verify an incoming message, the connector must know the sender's public key. For this you must
Expand Down Expand Up @@ -262,9 +262,19 @@ public class MyUftpMessageSupport implements UftpMessageSupport {

// ...
@Override
public Optional<PayloadMessageType> getPreviousMessage(String messageID, String recipientDomain) {
public Optional<PayloadMessageType> findDuplicateMessage(String messageID, String senderDomain, String recipientDomain) {
// Add the retrieval of the previous message here....
}

@Override
public <T extends PayloadMessageType> Optional<T> findReferencedMessage(UftpMessageReference<T> reference) {
// Add the retrieval of the referenced message here....
}

@Override
public Optional<FlexOfferRevocation> findFlexRevocation(String conversationID, String flexOfferMessageID, String senderDomain, String recipientDomain) {
// Add the retrieval of the revocation message here....
}
}
```

Expand All @@ -276,7 +286,7 @@ interface;
public class MyCongestionPointSupport implements CongestionPointSupport {

@Override
public boolean areKnownCongestionPoints(Collection<String> connectionPoints) {
public boolean areKnownCongestionPoints(Collection<EntityAddress> congestionPoints) {
// connect this to your local administration of congestion points
}
}
Expand Down Expand Up @@ -307,7 +317,7 @@ public class MyCustomValidator implements UftpUserDefinedValidator<FlexRequest>
}

@Override
public boolean valid(UftpParticipant sender, FlexRequest flexRequest) {
public boolean valid(UftpMessage<T> uftpMessage) {
// implement your validation logic here; return true if valid, false otherwise
}

Expand Down Expand Up @@ -341,7 +351,7 @@ public class OutgoingMessageHandler implements UftpOutgoingHandler<FlexRequest>
}

@Override
public void handle(UftpParticipant sender, FlexRequest message) {
public void handle(OutgoingUftpMessage<T> message) {
// call UftpSendMessageService immediately or queue message for sending later
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2024 Contributors to the Shapeshifter project
//
// SPDX-License-Identifier: Apache-2.0

package org.lfenergy.shapeshifter.core.model;

import org.lfenergy.shapeshifter.api.PayloadMessageType;

public final class IncomingUftpMessage<T extends PayloadMessageType> extends UftpMessage<T> {

private final String signedMessageXml;
private final String payloadMessageXml;

private IncomingUftpMessage(UftpParticipant sender, T payloadMessage, String signedMessageXml, String payloadMessageXml) {
super(sender, payloadMessage);
this.signedMessageXml = signedMessageXml;
this.payloadMessageXml = payloadMessageXml;
}

public static <T extends PayloadMessageType> IncomingUftpMessage<T> create(UftpParticipant sender, T payloadMessage, String signedMessageXml, String payloadMessageXml) {
return new IncomingUftpMessage<>(sender, payloadMessage, signedMessageXml, payloadMessageXml);
}

@Override
public UftpMessageDirection direction() {
return UftpMessageDirection.INCOMING;
}

public String signedMessageXml() {
return signedMessageXml;
}

public String payloadMessageXml() {
return payloadMessageXml;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2024 Contributors to the Shapeshifter project
//
// SPDX-License-Identifier: Apache-2.0

package org.lfenergy.shapeshifter.core.model;

import org.lfenergy.shapeshifter.api.PayloadMessageType;

public final class OutgoingUftpMessage<T extends PayloadMessageType> extends UftpMessage<T> {

private OutgoingUftpMessage(UftpParticipant sender, T payloadMessage) {
super(sender, payloadMessage);
}

public static <T extends PayloadMessageType> OutgoingUftpMessage<T> create(UftpParticipant sender, T payloadMessage) {
return new OutgoingUftpMessage<>(sender, payloadMessage);
}

@Override
public UftpMessageDirection direction() {
return UftpMessageDirection.OUTGOING;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,22 @@
import org.lfenergy.shapeshifter.api.PayloadMessageType;
import org.lfenergy.shapeshifter.api.TestMessageResponse;

public record UftpMessage<T extends PayloadMessageType>(
UftpParticipant sender,
UftpMessageDirection direction,
T payloadMessage
) {

public static <T extends PayloadMessageType> UftpMessage<T> createIncoming(UftpParticipant sender, T payloadMessage) {
return new UftpMessage<>(sender, UftpMessageDirection.INCOMING, payloadMessage);
public abstract sealed class UftpMessage<T extends PayloadMessageType> permits IncomingUftpMessage, OutgoingUftpMessage {

private final UftpParticipant sender;
private final T payloadMessage;

protected UftpMessage(UftpParticipant sender, T payloadMessage) {
this.sender = sender;
this.payloadMessage = payloadMessage;
}

public static <T extends PayloadMessageType> UftpMessage<T> createOutgoing(UftpParticipant sender, T payloadMessage) {
return new UftpMessage<>(sender, UftpMessageDirection.OUTGOING, payloadMessage);
public static <T extends PayloadMessageType> IncomingUftpMessage<T> createIncoming(UftpParticipant sender, T payloadMessage, String signedMessageXml, String payloadMessageXml) {
return IncomingUftpMessage.create(sender, payloadMessage, signedMessageXml, payloadMessageXml);
}

public static <T extends PayloadMessageType> OutgoingUftpMessage<T> createOutgoing(UftpParticipant sender, T payloadMessage) {
return OutgoingUftpMessage.create(sender, payloadMessage);
}

/**
Expand All @@ -36,7 +40,7 @@ public <U extends PayloadMessageType> UftpMessageReference<U> referenceToPreviou
return new UftpMessageReference<>(referencedMessageID,
conversationID,
// Having the correct direction is crucial for distinguishing between sender and recipient domain
direction.inverse(),
direction().inverse(),
// Flip domains as the referencing message is sent by the recipient of the referenced message
payloadMessage.getRecipientDomain(),
payloadMessage.getSenderDomain(),
Expand All @@ -46,4 +50,14 @@ public <U extends PayloadMessageType> UftpMessageReference<U> referenceToPreviou
public static boolean isResponse(PayloadMessageType message) {
return message instanceof PayloadMessageResponseType || message instanceof TestMessageResponse;
}

public UftpParticipant sender() {
return sender;
}

public T payloadMessage() {
return payloadMessage;
}

public abstract UftpMessageDirection direction();
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,35 @@
package org.lfenergy.shapeshifter.core.service.handler;

import org.lfenergy.shapeshifter.api.PayloadMessageType;
import org.lfenergy.shapeshifter.core.model.IncomingUftpMessage;
import org.lfenergy.shapeshifter.core.model.OutgoingUftpMessage;
import org.lfenergy.shapeshifter.core.model.UftpParticipant;

public interface UftpPayloadHandler {

void notifyNewIncomingMessage(UftpParticipant from, PayloadMessageType message);
/**
* @deprecated This method will be removed in the future. Use {@link #notifyNewIncomingMessage(IncomingUftpMessage)} instead.
*/
@Deprecated(forRemoval = true, since = "2.3.0")
default void notifyNewIncomingMessage(UftpParticipant from, PayloadMessageType message) {
// Default implementation to allow switching to the new method without breaking later when it's removed.
throw new UnsupportedOperationException("Deprecated for removal");
}

void notifyNewOutgoingMessage(UftpParticipant from, PayloadMessageType message);
default void notifyNewIncomingMessage(IncomingUftpMessage<? extends PayloadMessageType> message) {
notifyNewIncomingMessage(message.sender(), message.payloadMessage());
}

/**
* @deprecated This method will be removed in the future. Use {@link #notifyNewOutgoingMessage(OutgoingUftpMessage)} instead.
*/
@Deprecated(forRemoval = true, since = "2.3.0")
default void notifyNewOutgoingMessage(UftpParticipant from, PayloadMessageType message) {
// Default implementation to allow switching to the new method without breaking later when it's removed.
throw new UnsupportedOperationException("Deprecated for removal");
}

default void notifyNewOutgoingMessage(OutgoingUftpMessage<? extends PayloadMessageType> message) {
notifyNewOutgoingMessage(message.sender(), message.payloadMessage());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.apachecommons.CommonsLog;
import org.lfenergy.shapeshifter.api.PayloadMessageType;
import org.lfenergy.shapeshifter.api.SignedMessage;
import org.lfenergy.shapeshifter.core.model.IncomingUftpMessage;
import org.lfenergy.shapeshifter.core.model.UftpParticipant;
import org.lfenergy.shapeshifter.core.service.UftpErrorProcessor;
import org.lfenergy.shapeshifter.core.service.handler.UftpPayloadHandler;
import org.lfenergy.shapeshifter.core.service.receiving.DuplicateMessageDetection.DuplicateMessageResult;

/**
* This is an internal API and should not be used by applications. It may change or be removed in a future release.
*/
@CommonsLog
@RequiredArgsConstructor
public class ReceivedMessageProcessor {
Expand All @@ -21,16 +24,17 @@ public class ReceivedMessageProcessor {
private final DuplicateMessageDetection duplicateDetection;
private final UftpErrorProcessor errorProcessor;

public void onReceivedMessage(SignedMessage signedMessage, PayloadMessageType request) {
var sender = new UftpParticipant(signedMessage);
public void onReceivedMessage(IncomingUftpMessage<? extends PayloadMessageType> message) {
var request = message.payloadMessage();
var sender = message.sender();
log.debug(String.format("Processing of received %s message from %s", request.getClass().getSimpleName(), sender));

if (isDuplicateMessage(sender, request)) {
throw new DuplicateMessageException(
"Received " + request.getClass().getSimpleName() + " with MessageID '" + request.getMessageID() + "' from " + sender + " is a duplicate and has already been received.");
}

payloadHandler.notifyNewIncomingMessage(sender, request);
payloadHandler.notifyNewIncomingMessage(message);
}

private boolean isDuplicateMessage(UftpParticipant sender, PayloadMessageType payloadMessage) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.apachecommons.CommonsLog;
import org.lfenergy.shapeshifter.api.PayloadMessageType;
import org.lfenergy.shapeshifter.core.model.IncomingUftpMessage;
import org.lfenergy.shapeshifter.core.model.UftpMessage;
import org.lfenergy.shapeshifter.core.model.UftpParticipant;
import org.lfenergy.shapeshifter.core.service.handler.UftpPayloadHandler;
Expand Down Expand Up @@ -41,14 +42,36 @@ public class UftpReceivedMessageService {
* @param from The company uftp details of the recipient
* @param payloadMessage The details of the flex message, including messageID and conversationID
* @return The validation result, either `ok` or `rejected` including a rejection reason
* @deprecated This method will be removed in the future. Use {@link #process(IncomingUftpMessage)} instead.
*/
@Deprecated(forRemoval = true, since = "2.3.0")
public ValidationResult process(UftpParticipant from, PayloadMessageType payloadMessage) {
var validationResult = validateMessage(from, payloadMessage);
return process(IncomingUftpMessage.create(from, payloadMessage, null, null));
}

/**
* Processes an incoming flex message in a specific conversation. Can be called from within your own incoming flex message processor. When the message passed validation, a
* response message is created and sent.
*
* <pre><code>
* public void process(IncomingUftpMessage&lt;? extends PayloadMessageType&gt; message) {
* var validationResult = uftpReceivedMessageService.process(message);
*
* // implement further business logic here
* }
* </code></pre>
*
* @param uftpMessage The flex message
* @return The validation result, either `ok` or `rejected` including a rejection reason
*/
public <T extends PayloadMessageType> ValidationResult process(IncomingUftpMessage<T> uftpMessage) {
var validationResult = validateMessage(uftpMessage);

var payloadMessage = uftpMessage.payloadMessage();
if (UftpMessage.isResponse(payloadMessage)) {
processPayloadMessageResponse(payloadMessage, validationResult);
} else {
processPayloadMessage(from, payloadMessage, validationResult);
processPayloadMessage(uftpMessage.sender(), payloadMessage, validationResult);
}

return validationResult;
Expand All @@ -64,12 +87,12 @@ private void processPayloadMessage(UftpParticipant from, PayloadMessageType payl
var response = UftpValidationResponseCreator.getResponseForMessage(payloadMessage, validationResult);
var originalRecipient = new UftpParticipant(payloadMessage.getRecipientDomain(), getRecipientRoleBySenderRole(from.role()));

payloadHandler.notifyNewOutgoingMessage(originalRecipient, response);
payloadHandler.notifyNewOutgoingMessage(UftpMessage.createOutgoing(originalRecipient, response));
}

private ValidationResult validateMessage(UftpParticipant from, PayloadMessageType payloadMessage) {
private <T extends PayloadMessageType> ValidationResult validateMessage(UftpMessage<T> uftpMessage) {
if (shouldPerformValidations) {
return validationService.validate(UftpMessage.createIncoming(from, payloadMessage));
return validationService.validate(uftpMessage);
}
return ValidationResult.ok();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import org.lfenergy.shapeshifter.core.common.HttpStatusCode;
import org.lfenergy.shapeshifter.core.model.SigningDetails;
import org.lfenergy.shapeshifter.core.model.UftpMessage;
import org.lfenergy.shapeshifter.core.model.UftpMessageDirection;
import org.lfenergy.shapeshifter.core.model.UftpParticipant;
import org.lfenergy.shapeshifter.core.service.crypto.UftpCryptoService;
import org.lfenergy.shapeshifter.core.service.participant.ParticipantResolutionService;
Expand Down Expand Up @@ -106,7 +105,7 @@ public void attemptToSendMessage(@NonNull PayloadMessageType payloadMessage, @No
public void attemptToValidateAndSendMessage(@NonNull PayloadMessageType payloadMessage, @NonNull SigningDetails details) throws UftpSendException {
// We will validate outgoing messages, but we will not validate outgoing response messages.
if (!(payloadMessage instanceof PayloadMessageResponseType)) {
var uftpMessage = new UftpMessage<>(details.sender(), UftpMessageDirection.OUTGOING, payloadMessage);
var uftpMessage = UftpMessage.createOutgoing(details.sender(), payloadMessage);
var validationResult = uftpValidationService.validate(uftpMessage);
if (!validationResult.valid()) {
throw new UftpSendException(MessageFormat.format(MSG_VALIDATION_FAILED, payloadMessage.getClass().getSimpleName(), validationResult.rejectionReason()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ public interface CongestionPointSupport {
/**
* Checks whether every congestion point in a given list is a known congestion point
*
* @param connectionPoints The list of congestion points to be checked
* @param congestionPoints The list of congestion points to be checked
* @return Whether all given congestion points are a known congestion point
*/
boolean areKnownCongestionPoints(Collection<EntityAddress> connectionPoints);
boolean areKnownCongestionPoints(Collection<EntityAddress> congestionPoints);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,20 @@

public final class UftpMessageFixture {

private UftpMessageFixture() {
// Utility class
}

public static <T extends PayloadMessageType> UftpMessage<T> createIncoming(UftpParticipant sender, T payloadMessage) {
return new UftpMessage<>(sender, UftpMessageDirection.INCOMING, payloadMessage);
}
public static <T extends PayloadMessageResponseType> UftpMessage<T> createIncomingResponse(UftpParticipant sender, T payloadMessage) {
return new UftpMessage<>(sender, UftpMessageDirection.INCOMING, payloadMessage);
}

public static <T extends PayloadMessageType> UftpMessage<T> createOutgoing(UftpParticipant sender, T payloadMessage) {
return new UftpMessage<>(sender, UftpMessageDirection.OUTGOING, payloadMessage);
}
private UftpMessageFixture() {
// Utility class
}

public static <T extends PayloadMessageType> UftpMessage<T> createIncoming(UftpParticipant sender, T payloadMessage) {
return UftpMessage.createIncoming(sender, payloadMessage, "<SignedMessage/>", "<Payload/>");
}

public static <T extends PayloadMessageResponseType> UftpMessage<T> createIncomingResponse(UftpParticipant sender, T payloadMessage) {
return UftpMessage.createIncoming(sender, payloadMessage,"<SignedMessage/>", "<Payload/>");
}

public static <T extends PayloadMessageType> UftpMessage<T> createOutgoing(UftpParticipant sender, T payloadMessage) {
return UftpMessage.createOutgoing(sender, payloadMessage);
}

}
Loading