INT-684, Added new OrderAwareLinkedHashSet and modified AbstractDispatcher
This commit is contained in:
@@ -19,12 +19,11 @@ package org.springframework.integration.dispatcher;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.core.OrderComparator;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.task.TaskExecutor;
|
||||
@@ -46,12 +45,13 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Iwein Fuld
|
||||
* @author Oleg Zhurakousky
|
||||
*/
|
||||
public abstract class AbstractDispatcher implements MessageDispatcher {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(this.getClass());
|
||||
|
||||
private volatile List<MessageHandler> handlers = new LinkedList<MessageHandler>();
|
||||
private volatile Set<MessageHandler> handlers = new OrderedAwareLinkedHashSet<MessageHandler>();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private volatile Comparator<Object> comparator = new OrderComparator();
|
||||
@@ -85,32 +85,12 @@ public abstract class AbstractDispatcher implements MessageDispatcher {
|
||||
}
|
||||
|
||||
protected List<MessageHandler> getHandlers() {
|
||||
return Collections.unmodifiableList(this.handlers);
|
||||
return Collections.unmodifiableList(new ArrayList(this.handlers));
|
||||
}
|
||||
|
||||
public boolean addHandler(MessageHandler handler) {
|
||||
if (this.handlers.contains(handler)) {
|
||||
return false;
|
||||
}
|
||||
if (!this.hasOrder(handler)) {
|
||||
synchronized (this.handlerListMonitor) {
|
||||
return this.handlers.add(handler);
|
||||
}
|
||||
}
|
||||
synchronized (this.handlerListMonitor) {
|
||||
List<MessageHandler> orderedHandlers = new ArrayList<MessageHandler>();
|
||||
orderedHandlers.add(handler);
|
||||
List<MessageHandler> handlerList = new ArrayList<MessageHandler>(handlers);
|
||||
for (MessageHandler nextHandler : handlerList) {
|
||||
if (this.hasOrder(nextHandler)) {
|
||||
orderedHandlers.add(nextHandler);
|
||||
}
|
||||
}
|
||||
handlerList.removeAll(orderedHandlers);
|
||||
Collections.sort(orderedHandlers, this.comparator);
|
||||
orderedHandlers.addAll(handlerList);
|
||||
this.handlers = orderedHandlers;
|
||||
return true;
|
||||
return this.handlers.add(handler);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2002-2009 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.Comparator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.springframework.core.OrderComparator;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
/**
|
||||
*
|
||||
* Special Set that maintains the following semantics:
|
||||
* All elements that are un-ordered (do not implement {@link Ordered} interface or annotated {@link Order} annotation)
|
||||
* will be stored in the order in which they were added, maintaining the semantics of the {@link LinkedHashSet}.
|
||||
* However, there is a special {@link Comparator} (instantiated by default) for this implementation of {@link Set},
|
||||
* which is aware of the {@link Ordered} interface or and {@link Order} annotation. Those elements will have
|
||||
* precedence over un-ordered elements. If elements have the same order but themselves do not equal to one another
|
||||
* they will be placed to the right (appended next to) of the element with the same order, thus preserving the order
|
||||
* of the insertion and maintaining {@link LinkedHashSet} semantics.
|
||||
*
|
||||
* @author Oleg Zhurakousky
|
||||
* @since 1.0.3
|
||||
*/
|
||||
class OrderedAwareLinkedHashSet<E> extends LinkedHashSet<E> {
|
||||
private TreeSet orderedSet = new TreeSet(new EqualsAwareOrderComparator());
|
||||
/**
|
||||
* Every time when Ordered element is added via this method
|
||||
* this Set will be re-sorted, otherwise the element is simply added to the end of the stack.
|
||||
* If adding multiple objects for performance reasons it is recommended to use
|
||||
* addAll(Collection c) method which first adds all the elements to this set
|
||||
* and then calls reinitializeThis() method.
|
||||
*/
|
||||
public boolean add(E o){
|
||||
boolean present = this.doAdd(o);
|
||||
if (o instanceof Ordered){
|
||||
this.reinitializeThis();
|
||||
}
|
||||
return present;
|
||||
}
|
||||
/**
|
||||
* Adds all elements in this Collection and then resorts this set
|
||||
* via call to the reinitializeThis() method
|
||||
*/
|
||||
public boolean addAll(Collection<? extends E> c){
|
||||
Assert.notNull(c,"Can not merge with NULL set");
|
||||
if (CollectionUtils.isEmpty(c)){
|
||||
return false;
|
||||
}
|
||||
for (E object : c) {
|
||||
this.doAdd(object);
|
||||
}
|
||||
this.reinitializeThis();
|
||||
// due to the nature of previous method
|
||||
// at this point collection will always be modified
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param o
|
||||
* @return
|
||||
*/
|
||||
private boolean doAdd(E o){
|
||||
if (o instanceof Ordered){
|
||||
return orderedSet.add(o);
|
||||
} else {
|
||||
return super.add(o);
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private void reinitializeThis(){
|
||||
E[] tempUnorderedElements = (E[]) super.toArray();
|
||||
E[] tempOrderedElements = (E[]) orderedSet.toArray();
|
||||
super.clear();
|
||||
for (E object : tempOrderedElements) {
|
||||
super.add(object);
|
||||
}
|
||||
for (E object : tempUnorderedElements) {
|
||||
super.add(object);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Will reuse most of the functionality of OrderComparator, however if
|
||||
* elements have the same order, then 1 will be returned, thus positioning
|
||||
* such element to the right of the existing element.
|
||||
*/
|
||||
private static class EqualsAwareOrderComparator extends OrderComparator {
|
||||
public int compare(Object o1, Object o2) {
|
||||
int value = super.compare(o1, o2);
|
||||
// see if objects are not equal
|
||||
if (value == 0 && !o1.equals(o2)){
|
||||
return 1;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright 2002-2008 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.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.Ordered;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Oleg Zhurakousky
|
||||
* @since 1.0.3
|
||||
*/
|
||||
public class OrderedAwareLinkedHashSetTests {
|
||||
|
||||
/**
|
||||
* Tests that semantics of the LinkedHashSet were not broken
|
||||
*/
|
||||
@Test
|
||||
public void testAddUnordered(){
|
||||
OrderedAwareLinkedHashSet setToTest = new OrderedAwareLinkedHashSet();
|
||||
setToTest.add("foo");
|
||||
setToTest.add("bar");
|
||||
setToTest.add("baz");
|
||||
assertEquals(3, setToTest.size());
|
||||
Object[] elements = setToTest.toArray();
|
||||
assertEquals("foo", elements[0]);
|
||||
assertEquals("bar", elements[1]);
|
||||
assertEquals("baz", elements[2]);
|
||||
}
|
||||
/**
|
||||
* Tests that semantics of TreeSet(Comparator) were not broken.
|
||||
* However, there is a special Comparator (instantiated by default) for this implementation of Set,
|
||||
* which allows elements with the same "order" as long as these elements themselves are not equal.
|
||||
* In this case element with the same order will be placed to the right (appended next to) of
|
||||
* the already existing element, thus preserving the order of insertion (LinkedHashset semantics)
|
||||
* within the elements that have the same "order" value.
|
||||
*/
|
||||
@Test
|
||||
public void testAddOrdered(){
|
||||
OrderedAwareLinkedHashSet setToTest = new OrderedAwareLinkedHashSet();
|
||||
Object o1 = new Foo(3);
|
||||
Object o2 = new Foo(1);
|
||||
Object o3 = new Foo(2);
|
||||
Object o4 = new Foo(2);
|
||||
Object o5 = new Foo(Ordered.LOWEST_PRECEDENCE);
|
||||
Object o6 = new Foo(Ordered.LOWEST_PRECEDENCE);
|
||||
Object o7 = new Foo(Ordered.HIGHEST_PRECEDENCE);
|
||||
Object o8 = new Foo(Ordered.HIGHEST_PRECEDENCE);
|
||||
Object o9 = new Foo(4);
|
||||
Object o10 = new Foo(2);
|
||||
setToTest.add(o1);
|
||||
setToTest.add(o2);
|
||||
setToTest.add(o3);
|
||||
setToTest.add(o4);
|
||||
setToTest.add(o5);
|
||||
setToTest.add(o6);
|
||||
setToTest.add(o7);
|
||||
setToTest.add(o8);
|
||||
setToTest.add(o9);
|
||||
setToTest.add(o10);
|
||||
assertEquals(10, setToTest.size());
|
||||
System.out.println(setToTest);
|
||||
Object[] elements = setToTest.toArray();
|
||||
assertEquals(o7, elements[0]);
|
||||
assertEquals(o8, elements[1]);
|
||||
assertEquals(o2, elements[2]);
|
||||
assertEquals(o3, elements[3]);
|
||||
assertEquals(o4, elements[4]);
|
||||
assertEquals(o10, elements[5]);
|
||||
assertEquals(o1, elements[6]);
|
||||
assertEquals(o9, elements[7]);
|
||||
assertEquals(o5, elements[8]);
|
||||
assertEquals(o6, elements[9]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddAllOrderedUnordered(){
|
||||
List tempList = new ArrayList();
|
||||
Object o1 = new Foo(3);
|
||||
Object o2 = new Foo(1);
|
||||
Object o3 = "FooA";
|
||||
Object o4 = new Foo(2);
|
||||
Object o5 = new Foo(Ordered.LOWEST_PRECEDENCE);
|
||||
Object o6 = new Foo(Ordered.LOWEST_PRECEDENCE);
|
||||
Object o7 = new Foo(Ordered.HIGHEST_PRECEDENCE);
|
||||
Object o8 = new Foo(Ordered.HIGHEST_PRECEDENCE);
|
||||
Object o9 = new Foo(4);
|
||||
Object o10 = "FooB";
|
||||
tempList.add(o1);
|
||||
tempList.add(o2);
|
||||
tempList.add(o3);
|
||||
tempList.add(o4);
|
||||
tempList.add(o5);
|
||||
tempList.add(o6);
|
||||
tempList.add(o7);
|
||||
tempList.add(o8);
|
||||
tempList.add(o9);
|
||||
tempList.add(o10);
|
||||
assertEquals(10, tempList.size());
|
||||
OrderedAwareLinkedHashSet orderAwareSet = new OrderedAwareLinkedHashSet();
|
||||
orderAwareSet.addAll(tempList);
|
||||
System.out.println(orderAwareSet);
|
||||
Object[] elements = orderAwareSet.toArray();
|
||||
assertEquals(o7, elements[0]);
|
||||
assertEquals(o8, elements[1]);
|
||||
assertEquals(o2, elements[2]);
|
||||
assertEquals(o4, elements[3]);
|
||||
assertEquals(o1, elements[4]);
|
||||
assertEquals(o9, elements[5]);
|
||||
assertEquals(o5, elements[6]);
|
||||
assertEquals(o6, elements[7]);
|
||||
assertEquals(o3, elements[8]);
|
||||
assertEquals(o10, elements[9]);
|
||||
}
|
||||
|
||||
private static class Foo implements Ordered {
|
||||
private int order;
|
||||
public Foo(int order){
|
||||
this.order = order;
|
||||
}
|
||||
public int getOrder() {
|
||||
return order;
|
||||
}
|
||||
public String toString(){
|
||||
return "Foo-" + order;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user