1 | package fr.sii.ogham.sms.builder.cloudhopper; | |
2 | ||
3 | import static com.cloudhopper.smpp.SmppConstants.STATUS_ALYBND; | |
4 | import static com.cloudhopper.smpp.SmppConstants.STATUS_INVPASWD; | |
5 | import static com.cloudhopper.smpp.SmppConstants.STATUS_INVSERTYP; | |
6 | import static com.cloudhopper.smpp.SmppConstants.STATUS_INVSYSID; | |
7 | import static fr.sii.ogham.core.util.ExceptionUtils.fatalJvmError; | |
8 | import static fr.sii.ogham.core.util.ExceptionUtils.hasAnyCause; | |
9 | import static java.util.Arrays.asList; | |
10 | ||
11 | import java.util.function.Predicate; | |
12 | ||
13 | import com.cloudhopper.commons.gsm.DataCoding; | |
14 | import com.cloudhopper.smpp.type.SmppBindException; | |
15 | ||
16 | import fr.sii.ogham.sms.exception.message.EncodingException; | |
17 | import fr.sii.ogham.sms.sender.impl.cloudhopper.exception.DataCodingException; | |
18 | import fr.sii.ogham.sms.sender.impl.cloudhopper.exception.MessagePreparationException; | |
19 | ||
20 | /** | |
21 | * | |
22 | * @author Aurélien Baudet | |
23 | * | |
24 | */ | |
25 | public final class CloudhopperRetryablePredicates { | |
26 | ||
27 | private CloudhopperRetryablePredicates() { | |
28 | super(); | |
29 | } | |
30 | ||
31 | /** | |
32 | * Default predicate used to indicate if the error raised by Cloudhopper is | |
33 | * fatal or not. It returns {@code true} if the error is not fatal (means | |
34 | * that a new retry can be attempted). It returns {@code false} if the error | |
35 | * is fatal and no retry must be attempted. | |
36 | * | |
37 | * <p> | |
38 | * Here is the list of cases where there should have no retries: | |
39 | * <ul> | |
40 | * <li>There is a fatal JVM {@link Error} (like {@link OutOfMemoryError} for | |
41 | * example).</li> | |
42 | * <li>A bind request has been sent to the SMSC and it has responded with an | |
43 | * error indicating that the credentials are invalid</li> | |
44 | * <li>A bind request has been sent to the SMSC and it has responded with an | |
45 | * error indicating that the {@code system_type} is invalid</li> | |
46 | * <li>A bind request has been sent to the SMSC and it has responded with an | |
47 | * error indicating that client is already bound</li> | |
48 | * </ul> | |
49 | * | |
50 | * | |
51 | * @param error | |
52 | * the error to analyze | |
53 | * @return true if a connect may be retried | |
54 | */ | |
55 | @SuppressWarnings("squid:S1126") | |
56 | public static boolean canRetryConnecting(Throwable error) { | |
57 |
8
1. canRetryConnecting : negated conditional → NO_COVERAGE 2. canRetryConnecting : negated conditional → NO_COVERAGE 3. canRetryConnecting : negated conditional → NO_COVERAGE 4. canRetryConnecting : negated conditional → NO_COVERAGE 5. canRetryConnecting : negated conditional → KILLED 6. canRetryConnecting : negated conditional → KILLED 7. canRetryConnecting : negated conditional → KILLED 8. canRetryConnecting : negated conditional → KILLED |
if (fatalJvmError(error) || invalidCredentials(error) || invalidSystemType(error) || alreadyBound(error)) { |
58 |
2
1. canRetryConnecting : replaced boolean return with true for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::canRetryConnecting → NO_COVERAGE 2. canRetryConnecting : replaced boolean return with true for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::canRetryConnecting → KILLED |
return false; |
59 | } | |
60 |
2
1. canRetryConnecting : replaced boolean return with false for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::canRetryConnecting → NO_COVERAGE 2. canRetryConnecting : replaced boolean return with false for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::canRetryConnecting → KILLED |
return true; |
61 | } | |
62 | ||
63 | /** | |
64 | * Checks whether the error has been raised because the SMSC has sent a | |
65 | * response to a bind request indicating that the credentials are invalid | |
66 | * (wrong {@code system_id} or {@code password}). | |
67 | * | |
68 | * <p> | |
69 | * If the credentials are invalid, there is no point in retrying to connect. | |
70 | * | |
71 | * @param error | |
72 | * the raised error | |
73 | * @return true if the error is issued due to a bind failure (wrong | |
74 | * credentials) | |
75 | */ | |
76 | public static boolean invalidCredentials(Throwable error) { | |
77 |
2
1. invalidCredentials : negated conditional → NO_COVERAGE 2. invalidCredentials : negated conditional → TIMED_OUT |
if (error instanceof SmppBindException) { |
78 |
4
1. invalidCredentials : replaced boolean return with false for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::invalidCredentials → NO_COVERAGE 2. invalidCredentials : replaced boolean return with true for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::invalidCredentials → SURVIVED 3. invalidCredentials : replaced boolean return with true for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::invalidCredentials → NO_COVERAGE 4. invalidCredentials : replaced boolean return with false for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::invalidCredentials → KILLED |
return isCommandStatus((SmppBindException) error, STATUS_INVPASWD, STATUS_INVSYSID); |
79 | } | |
80 |
2
1. invalidCredentials : replaced boolean return with true for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::invalidCredentials → NO_COVERAGE 2. invalidCredentials : replaced boolean return with true for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::invalidCredentials → KILLED |
return false; |
81 | } | |
82 | ||
83 | /** | |
84 | * Checks whether the error has been raised because the SMSC has sent a | |
85 | * response to a bind request indicating that the {@code system_type} field | |
86 | * is invalid. | |
87 | * | |
88 | * <p> | |
89 | * If the {@code system_type} field is invalid, there is no point in | |
90 | * retrying to connect. | |
91 | * | |
92 | * @param error | |
93 | * the raised error | |
94 | * @return true if the error is issued due to a bind failure (wrong | |
95 | * {@code system_type}) | |
96 | */ | |
97 | public static boolean invalidSystemType(Throwable error) { | |
98 |
2
1. invalidSystemType : negated conditional → NO_COVERAGE 2. invalidSystemType : negated conditional → KILLED |
if (error instanceof SmppBindException) { |
99 |
2
1. invalidSystemType : replaced boolean return with false for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::invalidSystemType → NO_COVERAGE 2. invalidSystemType : replaced boolean return with true for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::invalidSystemType → NO_COVERAGE |
return isCommandStatus((SmppBindException) error, STATUS_INVSERTYP); |
100 | } | |
101 |
2
1. invalidSystemType : replaced boolean return with true for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::invalidSystemType → NO_COVERAGE 2. invalidSystemType : replaced boolean return with true for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::invalidSystemType → KILLED |
return false; |
102 | } | |
103 | ||
104 | /** | |
105 | * Checks whether the error has been raised because the SMSC has sent a | |
106 | * response to a bind request indicating that the client is already bound. | |
107 | * | |
108 | * <p> | |
109 | * If the client is already bound, there is no point in retrying to connect. | |
110 | * | |
111 | * @param error | |
112 | * the raised error | |
113 | * @return true if the error is issued due to a bind failure (already bound) | |
114 | */ | |
115 | public static boolean alreadyBound(Throwable error) { | |
116 |
2
1. alreadyBound : negated conditional → NO_COVERAGE 2. alreadyBound : negated conditional → KILLED |
if (error instanceof SmppBindException) { |
117 |
2
1. alreadyBound : replaced boolean return with false for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::alreadyBound → NO_COVERAGE 2. alreadyBound : replaced boolean return with true for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::alreadyBound → NO_COVERAGE |
return isCommandStatus((SmppBindException) error, STATUS_ALYBND); |
118 | } | |
119 |
2
1. alreadyBound : replaced boolean return with true for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::alreadyBound → NO_COVERAGE 2. alreadyBound : replaced boolean return with true for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::alreadyBound → KILLED |
return false; |
120 | } | |
121 | ||
122 | /** | |
123 | * Default predicate used to indicate if the error raised by Cloudhopper is | |
124 | * fatal or not. It returns {@code true} if the error is not fatal (means | |
125 | * that a new retry can be attempted). It returns {@code false} if the error | |
126 | * is fatal and no retry must be attempted. | |
127 | * | |
128 | * <p> | |
129 | * Here is the list of cases where there should have no retries: | |
130 | * <ul> | |
131 | * <li>There is a fatal JVM {@link Error} (like {@link OutOfMemoryError} for | |
132 | * example).</li> | |
133 | * <li>A bind request has been sent to the SMSC and it has responded with an | |
134 | * error indicating that the credentials are invalid</li> | |
135 | * <li>A bind request has been sent to the SMSC and it has responded with an | |
136 | * error indicating that the {@code system_type} is invalid</li> | |
137 | * <li>A bind request has been sent to the SMSC and it has responded with an | |
138 | * error indicating that client is already bound</li> | |
139 | * </ul> | |
140 | * | |
141 | * @return the predicate | |
142 | */ | |
143 | public static Predicate<Throwable> canRetryConnecting() { | |
144 |
2
1. canRetryConnecting : replaced return value with null for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::canRetryConnecting → SURVIVED 2. canRetryConnecting : replaced return value with null for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::canRetryConnecting → KILLED |
return CloudhopperRetryablePredicates::canRetryConnecting; |
145 | } | |
146 | ||
147 | /** | |
148 | * Predicate that skip retry if one of theses condition is met: | |
149 | * | |
150 | * If the error is due to a preparation error (not sending). In this case, | |
151 | * retrying will result in the same behavior so it will fail again: | |
152 | * <ul> | |
153 | * <li>Data coding couldn't be determined</li> | |
154 | * <li>Encoding couldn't be determined</li> | |
155 | * <li>Message preparation has failed</li> | |
156 | * </ul> | |
157 | * | |
158 | * <p> | |
159 | * In other situations, the message may be sent again. | |
160 | * | |
161 | * | |
162 | * @param error | |
163 | * the error to analyze | |
164 | * @return true if a connect may be retried | |
165 | */ | |
166 | @SuppressWarnings("squid:S1126") | |
167 | public static boolean canResendMessage(Throwable error) { | |
168 |
9
1. canResendMessage : negated conditional → SURVIVED 2. canResendMessage : negated conditional → NO_COVERAGE 3. canResendMessage : negated conditional → SURVIVED 4. canResendMessage : negated conditional → NO_COVERAGE 5. canResendMessage : negated conditional → SURVIVED 6. canResendMessage : negated conditional → NO_COVERAGE 7. canResendMessage : negated conditional → KILLED 8. canResendMessage : negated conditional → KILLED 9. canResendMessage : negated conditional → KILLED |
if (isDataCodingError(error) || isEncodingError(error) || messagePreparationFailed(error)) { |
169 |
2
1. canResendMessage : replaced boolean return with true for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::canResendMessage → NO_COVERAGE 2. canResendMessage : replaced boolean return with true for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::canResendMessage → SURVIVED |
return false; |
170 | } | |
171 | // @formatter:off | |
172 |
3
1. canResendMessage : negated conditional → SURVIVED 2. canResendMessage : negated conditional → NO_COVERAGE 3. canResendMessage : negated conditional → KILLED |
if (hasAnyCause(error, CloudhopperRetryablePredicates::isDataCodingError) |
173 |
3
1. canResendMessage : negated conditional → NO_COVERAGE 2. canResendMessage : negated conditional → SURVIVED 3. canResendMessage : negated conditional → KILLED |
|| hasAnyCause(error, CloudhopperRetryablePredicates::isEncodingError) |
174 |
3
1. canResendMessage : negated conditional → NO_COVERAGE 2. canResendMessage : negated conditional → KILLED 3. canResendMessage : negated conditional → KILLED |
|| hasAnyCause(error, CloudhopperRetryablePredicates::messagePreparationFailed)) { |
175 |
2
1. canResendMessage : replaced boolean return with true for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::canResendMessage → NO_COVERAGE 2. canResendMessage : replaced boolean return with true for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::canResendMessage → KILLED |
return false; |
176 | } | |
177 | // @formatter:on | |
178 |
3
1. canResendMessage : replaced boolean return with false for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::canResendMessage → SURVIVED 2. canResendMessage : replaced boolean return with false for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::canResendMessage → NO_COVERAGE 3. canResendMessage : replaced boolean return with false for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::canResendMessage → KILLED |
return true; |
179 | } | |
180 | ||
181 | /** | |
182 | * Indicates if the error is due to a {@link DataCoding} detection error. | |
183 | * | |
184 | * <p> | |
185 | * In this case, retrying will lead to the same error. | |
186 | * | |
187 | * @param error | |
188 | * the error to analyze | |
189 | * @return true if it is a data coding error | |
190 | */ | |
191 | public static boolean isDataCodingError(Throwable error) { | |
192 |
5
1. isDataCodingError : replaced boolean return with false for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::isDataCodingError → SURVIVED 2. isDataCodingError : replaced boolean return with false for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::isDataCodingError → NO_COVERAGE 3. isDataCodingError : replaced boolean return with true for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::isDataCodingError → NO_COVERAGE 4. isDataCodingError : replaced boolean return with true for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::isDataCodingError → SURVIVED 5. isDataCodingError : replaced boolean return with true for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::isDataCodingError → KILLED |
return error instanceof DataCodingException; |
193 | } | |
194 | ||
195 | /** | |
196 | * Indicates if the error is due to an encoding detection error. | |
197 | * | |
198 | * <p> | |
199 | * In this case, retrying will lead to the same error. | |
200 | * | |
201 | * @param error | |
202 | * the error to analyze | |
203 | * @return true if it is an encoding error | |
204 | */ | |
205 | public static boolean isEncodingError(Throwable error) { | |
206 |
5
1. isEncodingError : replaced boolean return with false for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::isEncodingError → NO_COVERAGE 2. isEncodingError : replaced boolean return with false for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::isEncodingError → SURVIVED 3. isEncodingError : replaced boolean return with true for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::isEncodingError → SURVIVED 4. isEncodingError : replaced boolean return with true for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::isEncodingError → NO_COVERAGE 5. isEncodingError : replaced boolean return with true for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::isEncodingError → KILLED |
return error instanceof EncodingException; |
207 | } | |
208 | ||
209 | /** | |
210 | * Indicates if the error is due to an error during preparation of the | |
211 | * message. | |
212 | * | |
213 | * <p> | |
214 | * In this case, retrying will lead to the same error. | |
215 | * | |
216 | * @param error | |
217 | * the error to analyze | |
218 | * @return true if it is a preparation error | |
219 | */ | |
220 | public static boolean messagePreparationFailed(Throwable error) { | |
221 |
6
1. messagePreparationFailed : replaced boolean return with false for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::messagePreparationFailed → SURVIVED 2. messagePreparationFailed : replaced boolean return with false for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::messagePreparationFailed → NO_COVERAGE 3. messagePreparationFailed : replaced boolean return with true for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::messagePreparationFailed → NO_COVERAGE 4. messagePreparationFailed : replaced boolean return with true for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::messagePreparationFailed → SURVIVED 5. messagePreparationFailed : replaced boolean return with false for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::messagePreparationFailed → KILLED 6. messagePreparationFailed : replaced boolean return with true for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::messagePreparationFailed → KILLED |
return error instanceof MessagePreparationException; |
222 | } | |
223 | ||
224 | /** | |
225 | * Predicate that skip retry if one of theses condition is met: | |
226 | * | |
227 | * If the error is due to a preparation error (not sending). In this case, | |
228 | * retrying will result in the same behavior so it will fail again: | |
229 | * <ul> | |
230 | * <li>Data coding couldn't be determined</li> | |
231 | * <li>Encoding couldn't be determined</li> | |
232 | * <li>Message preparation has failed</li> | |
233 | * </ul> | |
234 | * | |
235 | * <p> | |
236 | * In other situations, the message may be sent again. | |
237 | * | |
238 | * | |
239 | * @return the predicate that indicates if the message can be sent again | |
240 | */ | |
241 | public static Predicate<Throwable> canResendMessage() { | |
242 |
5
1. canResendMessage : replaced return value with null for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::canResendMessage → KILLED 2. canResendMessage : replaced return value with null for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::canResendMessage → KILLED 3. canResendMessage : replaced return value with null for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::canResendMessage → KILLED 4. canResendMessage : replaced return value with null for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::canResendMessage → KILLED 5. canResendMessage : replaced return value with null for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::canResendMessage → KILLED |
return CloudhopperRetryablePredicates::canResendMessage; |
243 | } | |
244 | ||
245 | private static boolean isCommandStatus(SmppBindException e, Integer... statuses) { | |
246 |
4
1. isCommandStatus : replaced boolean return with false for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::isCommandStatus → NO_COVERAGE 2. isCommandStatus : replaced boolean return with true for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::isCommandStatus → NO_COVERAGE 3. isCommandStatus : replaced boolean return with true for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::isCommandStatus → SURVIVED 4. isCommandStatus : replaced boolean return with false for fr/sii/ogham/sms/builder/cloudhopper/CloudhopperRetryablePredicates::isCommandStatus → KILLED |
return asList(statuses).contains(e.getBindResponse().getCommandStatus()); |
247 | } | |
248 | } | |
Mutations | ||
57 |
1.1 2.2 3.3 4.4 5.5 6.6 7.7 8.8 |
|
58 |
1.1 2.2 |
|
60 |
1.1 2.2 |
|
77 |
1.1 2.2 |
|
78 |
1.1 2.2 3.3 4.4 |
|
80 |
1.1 2.2 |
|
98 |
1.1 2.2 |
|
99 |
1.1 2.2 |
|
101 |
1.1 2.2 |
|
116 |
1.1 2.2 |
|
117 |
1.1 2.2 |
|
119 |
1.1 2.2 |
|
144 |
1.1 2.2 |
|
168 |
1.1 2.2 3.3 4.4 5.5 6.6 7.7 8.8 9.9 |
|
169 |
1.1 2.2 |
|
172 |
1.1 2.2 3.3 |
|
173 |
1.1 2.2 3.3 |
|
174 |
1.1 2.2 3.3 |
|
175 |
1.1 2.2 |
|
178 |
1.1 2.2 3.3 |
|
192 |
1.1 2.2 3.3 4.4 5.5 |
|
206 |
1.1 2.2 3.3 4.4 5.5 |
|
221 |
1.1 2.2 3.3 4.4 5.5 6.6 |
|
242 |
1.1 2.2 3.3 4.4 5.5 |
|
246 |
1.1 2.2 3.3 4.4 |