/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.component.sjms.tx;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.camel.CamelContext;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.sjms.BatchMessage;
import org.apache.camel.component.sjms.SjmsComponent;
import org.apache.camel.test.junit4.CamelTestSupport;
public abstract class BatchTransactedProducerSupport extends CamelTestSupport {
public abstract String getBrokerUri();
protected void runTest(String destinationName, int consumerRouteCount, int messageCount, int totalAttempts)
throws Exception {
// The CountDownLatch is used to make our final assertions await
// unit all the messages have been processed. It is also
// set to time out on the await. Our values are multiplied
// by the number of routes we have.
CountDownLatch latch = new CountDownLatch(totalAttempts + (messageCount * consumerRouteCount));
addRoute(destinationName, consumerRouteCount, latch);
// We should see the BatchMessage once in the prebatch and once in the
// redelivery. Then we should see 30 messages arrive in the postbatch.
getMockEndpoint("mock:test.producer").expectedMessageCount(totalAttempts);
for (int i = 1; i <= consumerRouteCount; i++) {
getMockEndpoint("mock:test.consumer." + i).expectedMessageCount(messageCount);
}
List<BatchMessage<String>> messages = new ArrayList<BatchMessage<String>>();
for (int i = 1; i <= messageCount; i++) {
String body = "Hello World " + i;
BatchMessage<String> message = new BatchMessage<String>(body, null);
messages.add(message);
}
// First we send the batch to capture the failure.
try {
log.info("Send Messages");
template.sendBody("direct:start", messages);
} catch (Exception e) {
log.info("Send Again");
template.sendBody("direct:start", messages);
}
// Await on our countdown for 10 seconds at most
// then move on
latch.await(10, TimeUnit.SECONDS);
assertMockEndpointsSatisfied(10, TimeUnit.SECONDS);
}
@Override
protected CamelContext createCamelContext() throws Exception {
CamelContext camelContext = super.createCamelContext();
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(getBrokerUri());
SjmsComponent component = new SjmsComponent();
component.setConnectionFactory(connectionFactory);
camelContext.addComponent("sjms", component);
return camelContext;
}
protected void addRoute(final String destinationName, final int consumerRouteCount, final CountDownLatch latch) throws Exception {
context.addRoutes(new RouteBuilder() {
@Override
public void configure() {
from("direct:start")
.id("producer.route")
.log("Producer Route Body: ${body}")
.to("mock:test.producer")
.to(destinationName + "?transacted=true")
// This Processor will force an exception to occur on the exchange
.process(new Processor() {
private final AtomicInteger counter = new AtomicInteger(0);
@Override
public void process(Exchange exchange) throws Exception {
// Only throw the exception the first time around.
// Otherwise allow it to proceed.
if (counter.getAndIncrement() == 0) {
log.info("BatchMessage received without redelivery. Rolling back.");
exchange.setException(new Exception());
}
// Countdown the latch
latch.countDown();
}
});
for (int i = 1; i <= consumerRouteCount; i++) {
from(destinationName)
.id("consumer.route." + i)
.log("Consumer Route " + i + " Body: ${body}")
.to("mock:test.consumer." + i)
.process(new Processor() {
@Override
public void process(Exchange exchange) throws Exception {
// Countdown the latch
latch.countDown();
}
});
}
}
});
}
}