Я разрабатываю службу уведомлений веб-крючков, которая позволяет клиентам подписываться/отписываться от сообщений, проходящих через промежуточное ПО, и получать уведомления о сообщениях (в соответствии с предоставленными критериями), отправляя полезную нагрузку сообщения на предоставленный URL-адрес обратного вызова. Доставка сообщения выглядит так:
flowBuilder
.enrichHeaders(e->e.header(MessageHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE,true))
.handle(Http.outboundChannelAdapter(message-> {
String subscriptionId = message.getHeaders().get(SUBSCRIPTION_ID_HEADER_NAME, String.class);
return subscriptionsStore.get(UUID.fromString(subscriptionId)).getCallbackUrl(); //potential NPE if subscription was removed
},restTemplateBuilder.build())
.get()
Как видите, реализация uriFunction извлекает URL-адрес обратного вызова из subscriptionsStore
по идентификатору подписки (часть заголовка сообщения).
Мой вопрос касается ситуации, когда клиент уже отписался со своим идентификатором подписки, и мне нужен условный обработчик.
Я знаю, что могу фильтровать сообщения с идентификатором подписки, которые все еще присутствуют в хранилище подписок, но это не правильное решение, так как клиент может отказаться от подписки между операциями filter
и handle
, все еще вызывая NRE в uriFunction
.
Другое решение состоит в том, чтобы получить заголовок с помощью URL-адреса обратного вызова и затем отфильтровать его по заголовку, имеющему непустое значение, но я не хочу ставить под угрозу ни заголовок, ни полезную нагрузку исходного сообщения.
Я могу подумать о другом подходе: вычислить URI несуществующих подписок как некоторое статическое значение и добавить перехватчик к RestTempalte
для имитации воспроизведения HTTP OK для этого конкретного значения URI...
Итак, мой вопрос о правильном способе обработки этого случая с использованием стандартного EIP или другой функции интеграции Spring, о которой я не знаю...
Спасибо
ОБНОВЛЕНИЕ
Я добавил класс DedicatedMessage
, который содержит контекст:
public static class DedicatedMessage extends GenericMessage<Object> implements MessageDecorator{
@Getter
@Transient
private Subscription subscription;
public DedicatedMessage(Subscription subscription,Object payload,Map<String,Object> headers) {
super(payload,headers);
this.subscription = subscription;
}
@Override
public Message<?> decorateMessage(Message<?> message) {
return new DedicatedMessage (subscription,message.getPayload(),message.getHeaders());
}
}
и изменил поток как:
flowBuilder
.enrichHeaders(e->e.header(MessageHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE,true))
.handle((payload, headers) -> {
String subscriptionId = (String) headers.get(SUBSCRIPTION_ID_HEADER_NAME);
Subscription subscription = subscriptionsCache.get(UUID.fromString(subscriptionId));
return Optional.ofNullable(subscription)
.map(s-> new DedicatedMessage(s, payload,headers))
.orElse(null);
})
.handle(Http.outboundChannelAdapter(message->((DedicatedMessage)message).getSubscription().getCallbackUrl()
,restTemplateBuilder.build())
.get()
Есть проблемы с этим подходом?