/* * Copyright 2002-2016 the original author or authors. * * Licensed 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.springframework.integration.dispatcher; import java.util.Collection; import java.util.Iterator; import java.util.concurrent.atomic.AtomicInteger; import org.springframework.messaging.Message; import org.springframework.messaging.MessageHandler; /** * Round-robin implementation of {@link LoadBalancingStrategy}. This * implementation will keep track of the index of the handler that has been * tried first and use a different starting handler every dispatch. * * @author Iwein Fuld * @author Mark Fisher * @author Oleg Zhurakousky * @since 1.0.3 */ public class RoundRobinLoadBalancingStrategy implements LoadBalancingStrategy { private final AtomicInteger currentHandlerIndex = new AtomicInteger(); /** * Returns an iterator that starts at a new point in the collection every time the * first part of the list that is skipped will be used at the end of the * iteration, so it guarantees all handlers are returned once on subsequent * <code>next()</code> invocations. */ public final Iterator<MessageHandler> getHandlerIterator(final Message<?> message, final Collection<MessageHandler> handlers) { int size = handlers.size(); if (size < 2) { this.getNextHandlerStartIndex(size); return handlers.iterator(); } return this.buildHandlerIterator(size, handlers.toArray(new MessageHandler[size])); } private Iterator<MessageHandler> buildHandlerIterator(int size, final MessageHandler[] handlers) { int nextHandlerStartIndex = getNextHandlerStartIndex(size); final MessageHandler[] reorderedHandlers = new MessageHandler[size]; System.arraycopy(handlers, nextHandlerStartIndex, reorderedHandlers, 0, size - nextHandlerStartIndex); System.arraycopy(handlers, 0, reorderedHandlers, size - nextHandlerStartIndex, 0 + nextHandlerStartIndex); return new Iterator<MessageHandler>() { int currentIndex = 0; public boolean hasNext() { return currentIndex < reorderedHandlers.length; } public MessageHandler next() { return reorderedHandlers[currentIndex++]; } public void remove() { throw new UnsupportedOperationException("Remove is not supported by this Iterator"); } }; } /** * Keeps track of the last index over multiple dispatches. Each invocation * of this method will increment the index by one, overflowing at * <code>size</code>. */ private int getNextHandlerStartIndex(int size) { if (size > 0) { int indexTail = this.currentHandlerIndex.getAndIncrement() % size; return indexTail < 0 ? indexTail + size : indexTail; } else { return size; } } }