MultiImplementationSender.java

1
package fr.sii.ogham.core.sender;
2
3
import static fr.sii.ogham.core.util.LogUtils.logString;
4
5
import java.lang.reflect.ParameterizedType;
6
import java.lang.reflect.Type;
7
import java.util.List;
8
9
import org.slf4j.Logger;
10
import org.slf4j.LoggerFactory;
11
12
import fr.sii.ogham.core.condition.Condition;
13
import fr.sii.ogham.core.exception.MessageException;
14
import fr.sii.ogham.core.message.Message;
15
import fr.sii.ogham.core.util.PriorizedList;
16
17
/**
18
 * Decorator sender that is able to handle a particular type of message. And for
19
 * handling this message it can rely on several possible implementations. Each
20
 * implementation is associated to a {@link Condition}. The condition indicates
21
 * at runtime if the message can be handled by the possible implementation.
22
 * There can be any kind of condition (for example, based on a required class in
23
 * the classpath or a particular property value...).
24
 * 
25
 * The implementation selection is done in the {@link #supports(Message)}
26
 * method.
27
 * 
28
 * @author Aurélien Baudet
29
 *
30
 * @param <M>
31
 *            The type of message that the implementations can handle
32
 * @see Condition
33
 */
34
public abstract class MultiImplementationSender<M extends Message> implements ConditionalSender {
35
	private static final Logger LOG = LoggerFactory.getLogger(MultiImplementationSender.class);
36
37
	/**
38
	 * The list of possible implementations indexed by the associated condition
39
	 */
40
	private final PriorizedList<Implementation> implementations;
41
42
	/**
43
	 * Initialize with no registered implementation.
44
	 */
45
	public MultiImplementationSender() {
46
		this(new PriorizedList<>());
47
	}
48
49
	/**
50
	 * Initialize with several implementations.
51
	 * 
52
	 * @param implementations
53
	 *            the list of possible implementations indexed by the condition
54
	 *            that indicates if the implementation is eligible at runtime
55
	 */
56
	public MultiImplementationSender(PriorizedList<Implementation> implementations) {
57
		super();
58
		this.implementations = implementations;
59
	}
60
61
	/**
62
	 * Register a new possible implementation with the associated condition. The
63
	 * implementation is added at the end so any other possible implementation
64
	 * will be used before this one if the associated condition allow it.
65
	 * 
66
	 * @param condition
67
	 *            the condition that indicates if the implementation can be used
68
	 *            at runtime
69
	 * @param implementation
70
	 *            the implementation to register
71
	 * @param priority
72
	 *            the registration priority
73
	 * @return this instance for fluent chaining
74
	 */
75
	public final MultiImplementationSender<M> addImplementation(Condition<Message> condition, MessageSender implementation, int priority) {
76
		implementations.register(new Implementation(condition, implementation), priority);
77 1 1. addImplementation : replaced return value with null for fr/sii/ogham/core/sender/MultiImplementationSender::addImplementation → RUN_ERROR
		return this;
78
	}
79
80
	@Override
81
	public boolean supports(Message message) {
82 2 1. supports : replaced boolean return with true for fr/sii/ogham/core/sender/MultiImplementationSender::supports → RUN_ERROR
2. supports : negated conditional → RUN_ERROR
		return getSender(message) != null;
83
	}
84
85
	@Override
86
	public void send(Message message) throws MessageException {
87
		MessageSender sender = getSender(message);
88 1 1. send : negated conditional → RUN_ERROR
		if (sender == null) {
89
			LOG.warn("No implementation is able to send the message {}. Skipping", logString(message));
90
			return;
91
		}
92
		LOG.debug("Sending message {} using {} implementation", logString(message), sender);
93 1 1. send : removed call to fr/sii/ogham/core/sender/MessageSender::send → RUN_ERROR
		sender.send(message);
94
	}
95
96
	public List<Implementation> getImplementations() {
97 1 1. getImplementations : replaced return value with Collections.emptyList for fr/sii/ogham/core/sender/MultiImplementationSender::getImplementations → RUN_ERROR
		return implementations.getOrdered();
98
	}
99
100
	protected boolean supportsMessageType(Message message) {
101
		Class<M> managedClass = getManagedClass();
102 1 1. supportsMessageType : negated conditional → RUN_ERROR
		if (managedClass == null) {
103
			LOG.warn("No managed class is declared");
104 1 1. supportsMessageType : replaced boolean return with true for fr/sii/ogham/core/sender/MultiImplementationSender::supportsMessageType → NO_COVERAGE
			return false;
105
		}
106 2 1. supportsMessageType : replaced boolean return with true for fr/sii/ogham/core/sender/MultiImplementationSender::supportsMessageType → RUN_ERROR
2. supportsMessageType : replaced boolean return with false for fr/sii/ogham/core/sender/MultiImplementationSender::supportsMessageType → RUN_ERROR
		return managedClass.isAssignableFrom(message.getClass());
107
	}
108
109
	@SuppressWarnings("unchecked")
110
	protected Class<M> getManagedClass() {
111
		Type genericSuperclass = getClass().getGenericSuperclass();
112 1 1. getManagedClass : negated conditional → RUN_ERROR
		if (genericSuperclass instanceof ParameterizedType) {
113 1 1. getManagedClass : replaced return value with null for fr/sii/ogham/core/sender/MultiImplementationSender::getManagedClass → RUN_ERROR
			return (Class<M>) ((ParameterizedType) genericSuperclass).getActualTypeArguments()[0];
114
		}
115
		return null;
116
	}
117
118
	private MessageSender getSender(Message message) {
119 1 1. getSender : negated conditional → RUN_ERROR
		if (supportsMessageType(message)) {
120
			LOG.debug("Can handle the message type {}. Is there any implementation available to send it ?", message.getClass());
121
			for (Implementation impl : implementations.getOrdered()) {
122 1 1. getSender : negated conditional → RUN_ERROR
				if (impl.getCondition().accept(message)) {
123
					LOG.debug("The implementation {} can handle the message {}", impl.getSender(), logString(message));
124 1 1. getSender : replaced return value with null for fr/sii/ogham/core/sender/MultiImplementationSender::getSender → RUN_ERROR
					return impl.getSender();
125
				}
126
			}
127
		}
128
		LOG.debug("Can't handle the message type {}", message.getClass());
129
		return null;
130
	}
131
132
	public static class Implementation {
133
		private final Condition<Message> condition;
134
		private final MessageSender sender;
135
136
		public Implementation(Condition<Message> condition, MessageSender sender) {
137
			super();
138
			this.condition = condition;
139
			this.sender = sender;
140
		}
141
142
		public Condition<Message> getCondition() {
143 1 1. getCondition : replaced return value with null for fr/sii/ogham/core/sender/MultiImplementationSender$Implementation::getCondition → RUN_ERROR
			return condition;
144
		}
145
146
		public MessageSender getSender() {
147 1 1. getSender : replaced return value with null for fr/sii/ogham/core/sender/MultiImplementationSender$Implementation::getSender → RUN_ERROR
			return sender;
148
		}
149
	}
150
}

Mutations

77

1.1
Location : addImplementation
Killed by :
replaced return value with null for fr/sii/ogham/core/sender/MultiImplementationSender::addImplementation → RUN_ERROR

82

1.1
Location : supports
Killed by :
replaced boolean return with true for fr/sii/ogham/core/sender/MultiImplementationSender::supports → RUN_ERROR

2.2
Location : supports
Killed by :
negated conditional → RUN_ERROR

88

1.1
Location : send
Killed by :
negated conditional → RUN_ERROR

93

1.1
Location : send
Killed by :
removed call to fr/sii/ogham/core/sender/MessageSender::send → RUN_ERROR

97

1.1
Location : getImplementations
Killed by :
replaced return value with Collections.emptyList for fr/sii/ogham/core/sender/MultiImplementationSender::getImplementations → RUN_ERROR

102

1.1
Location : supportsMessageType
Killed by :
negated conditional → RUN_ERROR

104

1.1
Location : supportsMessageType
Killed by :
replaced boolean return with true for fr/sii/ogham/core/sender/MultiImplementationSender::supportsMessageType → NO_COVERAGE

106

1.1
Location : supportsMessageType
Killed by :
replaced boolean return with true for fr/sii/ogham/core/sender/MultiImplementationSender::supportsMessageType → RUN_ERROR

2.2
Location : supportsMessageType
Killed by :
replaced boolean return with false for fr/sii/ogham/core/sender/MultiImplementationSender::supportsMessageType → RUN_ERROR

112

1.1
Location : getManagedClass
Killed by :
negated conditional → RUN_ERROR

113

1.1
Location : getManagedClass
Killed by :
replaced return value with null for fr/sii/ogham/core/sender/MultiImplementationSender::getManagedClass → RUN_ERROR

119

1.1
Location : getSender
Killed by :
negated conditional → RUN_ERROR

122

1.1
Location : getSender
Killed by :
negated conditional → RUN_ERROR

124

1.1
Location : getSender
Killed by :
replaced return value with null for fr/sii/ogham/core/sender/MultiImplementationSender::getSender → RUN_ERROR

143

1.1
Location : getCondition
Killed by :
replaced return value with null for fr/sii/ogham/core/sender/MultiImplementationSender$Implementation::getCondition → RUN_ERROR

147

1.1
Location : getSender
Killed by :
replaced return value with null for fr/sii/ogham/core/sender/MultiImplementationSender$Implementation::getSender → RUN_ERROR

Active mutators

Tests examined


Report generated by PIT 1.13.1