Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2016 esbtools Contributors and/or its affiliates.
*
* This file is part of esbtools.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
package org.esbtools.eventhandler;
import org.apache.camel.builder.RouteBuilder;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
public class AsyncBatchMessageProcessorRoute extends RouteBuilder {
private final String fromUri;
private final String failureUri;
private final Duration processTimeout;
private final MessageFactory messageFactory;
private final int idCount = idCounter.getAndIncrement();
private final String routeId = "messageProcessor-" + idCount;
private static final AtomicInteger idCounter = new AtomicInteger(0);
/**
* @param fromUri Endpoint to consume from, expected to create exchanges with bodies instances
* of {@link Collection}. The elements of this collection will be provided to
* {@code messageFactory} to parse them into {@link Message}s.
* @param failureUri Endpoint where failures will be sent to as a {@code Collection} of
* {@link FailedMessage}s.
* @param processTimeout How to long to wait for a message process before timing out?
* @param messageFactory Accepts each element in the exchange body {@code Collection} and
* parses them to create message implementations which will be processed.
*/
public AsyncBatchMessageProcessorRoute(String fromUri, String failureUri,
Duration processTimeout, MessageFactory messageFactory) {
this.fromUri = Objects.requireNonNull(fromUri, "fromUri");
this.failureUri = Objects.requireNonNull(failureUri, "failureUri");
this.processTimeout = Objects.requireNonNull(processTimeout, "processTimeout");
this.messageFactory = Objects.requireNonNull(messageFactory, "messageFactory");
}
@Override
public void configure() throws Exception {
from(fromUri)
.routeId(routeId)
.process(exchange -> {
Object exchangeBody = exchange.getIn().getBody();
if (!(exchangeBody instanceof Collection)) {
throw new IllegalArgumentException("Expected `fromUri` to deliver exchanges with " +
"Collection bodies so that we may batch process for efficiency. However, " +
"the uri '" + fromUri + "' returned " +
((exchangeBody == null)
? "null."
: "the " + exchangeBody.getClass().getName() + ": " + exchangeBody));
}
Collection originalMessages = (Collection) exchangeBody;
List processingMessages = new ArrayList<>(originalMessages.size());
List failures = new ArrayList<>();
log.debug("Received {} messages on route {}: {}",
originalMessages.size(), routeId, originalMessages);
// Start processing all of the messages in the batch in parallel.
for (Object originalMessage : originalMessages) {
final Message message;
try {
message = messageFactory.getMessageForBody(originalMessage);
} catch (Exception e) {
log.error("Failure parsing message. Body was: " + originalMessage, e);
failures.add(new FailedMessage(originalMessage, e));
continue;
}
final Future processingFuture;
try {
processingFuture = message.process();
} catch (Exception e) {
log.error("Failed to process message: " + message, e);
FailedMessage failure = new FailedMessage(originalMessage, message, e);
failures.add(failure);
continue;
}
ProcessingMessage processing = new ProcessingMessage(
originalMessage, message, processingFuture);
processingMessages.add(processing);
}
List processedSuccessfully = log.isDebugEnabled()
? new ArrayList<>(processingMessages.size())
: Collections.emptyList();
// Wait for processing to complete.
for (ProcessingMessage processingMsg : processingMessages) {
try {
processingMsg.future.get(processTimeout.toMillis(), TimeUnit.MILLISECONDS);
if (log.isDebugEnabled()) {
processedSuccessfully.add(processingMsg.parsedMessage);
}
} catch (ExecutionException e) {
log.error("Failed to process message: " + processingMsg.parsedMessage, e);
FailedMessage failure = new FailedMessage(processingMsg.originalMessage,
processingMsg.parsedMessage, e.getCause());
failures.add(failure);
} catch (InterruptedException | TimeoutException e) {
log.warn("Timed out processing message: " + processingMsg.parsedMessage, e);
FailedMessage failure = new FailedMessage(
processingMsg.originalMessage, processingMsg.parsedMessage, e);
failures.add(failure);
}
}
log.debug("Processed {}/{} messages on route {}: {}",
processedSuccessfully.size(), originalMessages.size(),
routeId, processedSuccessfully);
// Deal with failures...
exchange.getIn().setBody(failures);
})
.to(failureUri);
}
/**
* Simple struct for storing a message and its future processing result.
*/
private static class ProcessingMessage {
final Object originalMessage;
final Message parsedMessage;
final Future future;
ProcessingMessage(Object originalMessage, Message parsedMessage, Future future) {
this.originalMessage = originalMessage;
this.parsedMessage = parsedMessage;
this.future = future;
}
}
}