BaseMessagePreparator.java

1
package fr.sii.ogham.sms.sender.impl.cloudhopper.preparator;
2
3
import static com.cloudhopper.smpp.SmppConstants.ESM_CLASS_UDHI_MASK;
4
5
import java.util.ArrayList;
6
import java.util.List;
7
8
import org.slf4j.Logger;
9
import org.slf4j.LoggerFactory;
10
11
import com.cloudhopper.smpp.pdu.SubmitSm;
12
import com.cloudhopper.smpp.type.Address;
13
14
import fr.sii.ogham.core.exception.InvalidMessageException;
15
import fr.sii.ogham.sms.encoder.Encoded;
16
import fr.sii.ogham.sms.exception.message.PhoneNumberTranslatorException;
17
import fr.sii.ogham.sms.exception.message.SplitMessageException;
18
import fr.sii.ogham.sms.message.Contact;
19
import fr.sii.ogham.sms.message.PhoneNumber;
20
import fr.sii.ogham.sms.message.Recipient;
21
import fr.sii.ogham.sms.message.Sms;
22
import fr.sii.ogham.sms.message.addressing.AddressedPhoneNumber;
23
import fr.sii.ogham.sms.message.addressing.translator.PhoneNumberTranslator;
24
import fr.sii.ogham.sms.sender.impl.cloudhopper.exception.DataCodingException;
25
import fr.sii.ogham.sms.sender.impl.cloudhopper.exception.MessagePreparationException;
26
import fr.sii.ogham.sms.splitter.EncodedSegment;
27
import fr.sii.ogham.sms.splitter.MessageSplitter;
28
import fr.sii.ogham.sms.splitter.Segment;
29
30
/**
31
 * Base preparator that creates {@link SubmitSm}s.
32
 * 
33
 * <p>
34
 * The message content is not set. It lets implementations implement
35
 * {@code fill(SubmitSm, Segment)} method to set the content.
36
 * 
37
 * <p>
38
 * This preparator detects which charset should be used to encode message string
39
 * and splits it if needed. It also converts {@link PhoneNumber} to
40
 * {@link AddressedPhoneNumber}.
41
 * 
42
 * @author Aurélien Baudet
43
 *
44
 */
45
public abstract class BaseMessagePreparator implements MessagePreparator {
46
	private static final Logger LOG = LoggerFactory.getLogger(BaseMessagePreparator.class);
47
48
	/**
49
	 * Split message if needed into several parts
50
	 */
51
	private final MessageSplitter messageSplitter;
52
53
	/**
54
	 * Determines the data coding to use according to encoding
55
	 */
56
	private final DataCodingProvider dataCodingProvider;
57
58
	/**
59
	 * This phone number translator will handle the fallback addressing policy
60
	 * (TON / NPI).
61
	 */
62
	private final PhoneNumberTranslator phoneNumberTranslator;
63
64
	/**
65
	 * The preparator can split messages and provide data coding information.
66
	 * 
67
	 * <p>
68
	 * The phone number won't be translated meaning that if phone number is not
69
	 * already converted to {@link AddressedPhoneNumber} then an
70
	 * {@link IllegalStateException} is thrown.
71
	 * 
72
	 * @param messageSplitter
73
	 *            Split message in several parts if needed
74
	 * @param dataCodingProvider
75
	 *            Determines the data coding to use according to encoding
76
	 */
77
	public BaseMessagePreparator(MessageSplitter messageSplitter, DataCodingProvider dataCodingProvider) {
78
		this(messageSplitter, dataCodingProvider, null);
79
	}
80
81
	/**
82
	 * Initializes the preparator with message splitter, data coding provider
83
	 * and phone number translator.
84
	 * 
85
	 * @param messageSplitter
86
	 *            Split message in several parts if needed
87
	 * @param dataCodingProvider
88
	 *            Determines the data coding to use according to encoding
89
	 * @param phoneNumberTranslator
90
	 *            Fallback phone translator to handle addressing policy
91
	 */
92
	public BaseMessagePreparator(MessageSplitter messageSplitter, DataCodingProvider dataCodingProvider, PhoneNumberTranslator phoneNumberTranslator) {
93
		super();
94
		this.messageSplitter = messageSplitter;
95
		this.dataCodingProvider = dataCodingProvider;
96
		this.phoneNumberTranslator = phoneNumberTranslator;
97
	}
98
99
	@Override
100
	public List<SubmitSm> prepareMessages(Sms message) throws MessagePreparationException {
101
		try {
102 1 1. prepareMessages : replaced return value with Collections.emptyList for fr/sii/ogham/sms/sender/impl/cloudhopper/preparator/BaseMessagePreparator::prepareMessages → RUN_ERROR
			return createMessages(message);
103
		} catch (PhoneNumberTranslatorException | DataCodingException | InvalidMessageException e) {
104
			throw new MessagePreparationException("Failed to prepare messages", message, e);
105
		} catch (SplitMessageException e) {
106
			throw new MessagePreparationException("Failed to split SMPP message before sending it", message, e);
107
		}
108
	}
109
110
	/**
111
	 * Fill the {@link SubmitSm} with the message content.
112
	 * 
113
	 * @param originalMessage
114
	 *            the SMS that is about to be sent
115
	 * @param submit
116
	 *            the submit to fill
117
	 * @param part
118
	 *            the message content
119
	 * @throws MessagePreparationException
120
	 *             when message couldn't be prepared correctly
121
	 */
122
	protected abstract void fill(Sms originalMessage, SubmitSm submit, Segment part) throws MessagePreparationException;
123
124
	private List<SubmitSm> createMessages(Sms message) throws PhoneNumberTranslatorException, SplitMessageException, DataCodingException, MessagePreparationException, InvalidMessageException {
125
		List<SubmitSm> messages = new ArrayList<>();
126
		for (Recipient recipient : message.getRecipients()) {
127
			messages.addAll(createMessages(message, recipient));
128
		}
129 1 1. createMessages : replaced return value with Collections.emptyList for fr/sii/ogham/sms/sender/impl/cloudhopper/preparator/BaseMessagePreparator::createMessages → RUN_ERROR
		return messages;
130
	}
131
132
	private List<SubmitSm> createMessages(Sms message, Recipient recipient) throws PhoneNumberTranslatorException, SplitMessageException, DataCodingException, MessagePreparationException, InvalidMessageException {
133
		List<SubmitSm> messages = new ArrayList<>();
134
135
		List<Segment> parts = messageSplitter.split(message.getContent().toString());
136 2 1. createMessages : negated conditional → RUN_ERROR
2. createMessages : changed conditional boundary → RUN_ERROR
		if (parts.size() <= 1) {
137 1 1. createMessages : removed call to fr/sii/ogham/sms/sender/impl/cloudhopper/preparator/BaseMessagePreparator::addSubmit → RUN_ERROR
			addSubmit(message, recipient, messages, parts.get(0));
138 1 1. createMessages : replaced return value with Collections.emptyList for fr/sii/ogham/sms/sender/impl/cloudhopper/preparator/BaseMessagePreparator::createMessages → RUN_ERROR
			return messages;
139
		}
140
141
		LOG.debug("Content split into {} parts", parts.size());
142
		for (Segment part : parts) {
143 1 1. createMessages : removed call to fr/sii/ogham/sms/sender/impl/cloudhopper/preparator/BaseMessagePreparator::addEsmClassSubmit → NO_COVERAGE
			addEsmClassSubmit(message, recipient, messages, part);
144
		}
145 1 1. createMessages : replaced return value with Collections.emptyList for fr/sii/ogham/sms/sender/impl/cloudhopper/preparator/BaseMessagePreparator::createMessages → NO_COVERAGE
		return messages;
146
	}
147
148
	private void addEsmClassSubmit(Sms message, Recipient recipient, List<SubmitSm> messages, Segment part) throws PhoneNumberTranslatorException, DataCodingException, MessagePreparationException, InvalidMessageException {
149
		SubmitSm submit = createMessage(message, recipient, part);
150 1 1. addEsmClassSubmit : removed call to com/cloudhopper/smpp/pdu/SubmitSm::setEsmClass → NO_COVERAGE
		submit.setEsmClass(ESM_CLASS_UDHI_MASK);
151
		messages.add(submit);
152
	}
153
154
	private void addSubmit(Sms message, Recipient recipient, List<SubmitSm> messages, Segment part) throws PhoneNumberTranslatorException, DataCodingException, MessagePreparationException, InvalidMessageException {
155
		SubmitSm submit = createMessage(message, recipient, part);
156
		messages.add(submit);
157
	}
158
159
	private SubmitSm createMessage(Sms message, Recipient recipient, Segment part) throws PhoneNumberTranslatorException, DataCodingException, MessagePreparationException, InvalidMessageException {
160
		SubmitSm submit = new SubmitSm();
161 1 1. createMessage : removed call to com/cloudhopper/smpp/pdu/SubmitSm::setSourceAddress → RUN_ERROR
		submit.setSourceAddress(toAddress("sender", message, message.getFrom()));
162 1 1. createMessage : removed call to com/cloudhopper/smpp/pdu/SubmitSm::setDestAddress → RUN_ERROR
		submit.setDestAddress(toAddress("recipient", message, recipient));
163
164 1 1. createMessage : negated conditional → RUN_ERROR
		if (part instanceof EncodedSegment) {
165
			Encoded encoded = ((EncodedSegment) part).getEncoded();
166 1 1. createMessage : removed call to com/cloudhopper/smpp/pdu/SubmitSm::setDataCoding → RUN_ERROR
			submit.setDataCoding(dataCodingProvider.provide(encoded).getByteValue());
167
		}
168
169 1 1. createMessage : removed call to fr/sii/ogham/sms/sender/impl/cloudhopper/preparator/BaseMessagePreparator::fill → RUN_ERROR
		fill(message, submit, part);
170
171 1 1. createMessage : replaced return value with null for fr/sii/ogham/sms/sender/impl/cloudhopper/preparator/BaseMessagePreparator::createMessage → RUN_ERROR
		return submit;
172
	}
173
174
	private Address toAddress(String field, Sms msg, Contact contact) throws PhoneNumberTranslatorException, InvalidMessageException {
175 1 1. toAddress : negated conditional → RUN_ERROR
		if (contact == null) {
176
			throw new InvalidMessageException(field+" is not set", msg, "Missing "+field+" phone number");
177
		}
178
		PhoneNumber phoneNumber = contact.getPhoneNumber();
179 1 1. toAddress : negated conditional → RUN_ERROR
		if (phoneNumber == null) {
180
			throw new InvalidMessageException(field+" phone number is not set", msg, "Missing "+field+" phone number");
181
		}
182 1 1. toAddress : replaced return value with null for fr/sii/ogham/sms/sender/impl/cloudhopper/preparator/BaseMessagePreparator::toAddress → RUN_ERROR
		return toAddress(phoneNumber);
183
	}
184
	
185
	/**
186
	 * Transforms a {@link PhoneNumber} in a {@link Address} type.
187
	 * 
188
	 * @param phoneNumber
189
	 *            The given phone number
190
	 * @return corresponding address with number, TON and NPI
191
	 * @throws PhoneNumberTranslatorException
192
	 *             If an error occurs during fallback phone number translation
193
	 */
194
	private Address toAddress(PhoneNumber phoneNumber) throws PhoneNumberTranslatorException {
195
		AddressedPhoneNumber addressedPhoneNumber;
196
197 1 1. toAddress : negated conditional → RUN_ERROR
		if (phoneNumber instanceof AddressedPhoneNumber) {
198
			addressedPhoneNumber = (AddressedPhoneNumber) phoneNumber;
199 1 1. toAddress : negated conditional → NO_COVERAGE
		} else if (phoneNumberTranslator != null) {
200
			LOG.warn("Fallback addressing policy used for PhoneNumber '{}'. You might decorate your sender with a PhoneNumberTranslatorSender.", phoneNumber);
201
			addressedPhoneNumber = phoneNumberTranslator.translate(phoneNumber);
202
		} else {
203
			throw new IllegalStateException("Must provide addressing policy with the phone number or with a fallback phone number translator.");
204
		}
205
		LOG.debug("Addressing policy applied on {} ", addressedPhoneNumber);
206 1 1. toAddress : replaced return value with null for fr/sii/ogham/sms/sender/impl/cloudhopper/preparator/BaseMessagePreparator::toAddress → RUN_ERROR
		return new Address(addressedPhoneNumber.getTon().value(), addressedPhoneNumber.getNpi().value(), addressedPhoneNumber.getNumber());
207
	}
208
209
}

Mutations

102

1.1
Location : prepareMessages
Killed by :
replaced return value with Collections.emptyList for fr/sii/ogham/sms/sender/impl/cloudhopper/preparator/BaseMessagePreparator::prepareMessages → RUN_ERROR

129

1.1
Location : createMessages
Killed by :
replaced return value with Collections.emptyList for fr/sii/ogham/sms/sender/impl/cloudhopper/preparator/BaseMessagePreparator::createMessages → RUN_ERROR

136

1.1
Location : createMessages
Killed by :
negated conditional → RUN_ERROR

2.2
Location : createMessages
Killed by :
changed conditional boundary → RUN_ERROR

137

1.1
Location : createMessages
Killed by :
removed call to fr/sii/ogham/sms/sender/impl/cloudhopper/preparator/BaseMessagePreparator::addSubmit → RUN_ERROR

138

1.1
Location : createMessages
Killed by :
replaced return value with Collections.emptyList for fr/sii/ogham/sms/sender/impl/cloudhopper/preparator/BaseMessagePreparator::createMessages → RUN_ERROR

143

1.1
Location : createMessages
Killed by :
removed call to fr/sii/ogham/sms/sender/impl/cloudhopper/preparator/BaseMessagePreparator::addEsmClassSubmit → NO_COVERAGE

145

1.1
Location : createMessages
Killed by :
replaced return value with Collections.emptyList for fr/sii/ogham/sms/sender/impl/cloudhopper/preparator/BaseMessagePreparator::createMessages → NO_COVERAGE

150

1.1
Location : addEsmClassSubmit
Killed by :
removed call to com/cloudhopper/smpp/pdu/SubmitSm::setEsmClass → NO_COVERAGE

161

1.1
Location : createMessage
Killed by :
removed call to com/cloudhopper/smpp/pdu/SubmitSm::setSourceAddress → RUN_ERROR

162

1.1
Location : createMessage
Killed by :
removed call to com/cloudhopper/smpp/pdu/SubmitSm::setDestAddress → RUN_ERROR

164

1.1
Location : createMessage
Killed by :
negated conditional → RUN_ERROR

166

1.1
Location : createMessage
Killed by :
removed call to com/cloudhopper/smpp/pdu/SubmitSm::setDataCoding → RUN_ERROR

169

1.1
Location : createMessage
Killed by :
removed call to fr/sii/ogham/sms/sender/impl/cloudhopper/preparator/BaseMessagePreparator::fill → RUN_ERROR

171

1.1
Location : createMessage
Killed by :
replaced return value with null for fr/sii/ogham/sms/sender/impl/cloudhopper/preparator/BaseMessagePreparator::createMessage → RUN_ERROR

175

1.1
Location : toAddress
Killed by :
negated conditional → RUN_ERROR

179

1.1
Location : toAddress
Killed by :
negated conditional → RUN_ERROR

182

1.1
Location : toAddress
Killed by :
replaced return value with null for fr/sii/ogham/sms/sender/impl/cloudhopper/preparator/BaseMessagePreparator::toAddress → RUN_ERROR

197

1.1
Location : toAddress
Killed by :
negated conditional → RUN_ERROR

199

1.1
Location : toAddress
Killed by :
negated conditional → NO_COVERAGE

206

1.1
Location : toAddress
Killed by :
replaced return value with null for fr/sii/ogham/sms/sender/impl/cloudhopper/preparator/BaseMessagePreparator::toAddress → RUN_ERROR

Active mutators

Tests examined


Report generated by PIT 1.13.1