Skip to content

Commit b2645ae

Browse files
committed
Reject SIRI messages with missing Order attribute on calls
1 parent e5a7cc5 commit b2645ae

File tree

6 files changed

+135
-6
lines changed

6 files changed

+135
-6
lines changed

application/src/main/java/org/opentripplanner/updater/spi/UpdateError.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ public enum UpdateErrorType {
4444
NO_FUZZY_TRIP_MATCH,
4545
MULTIPLE_FUZZY_TRIP_MATCHES,
4646
EMPTY_STOP_POINT_REF,
47+
MISSING_CALL_ORDER,
4748
NO_TRIP_FOR_CANCELLATION_FOUND,
4849
TRIP_ALREADY_EXISTS,
4950
NO_START_DATE,

application/src/main/java/org/opentripplanner/updater/trip/siri/CallWrapper.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
package org.opentripplanner.updater.trip.siri;
22

3+
import java.math.BigInteger;
34
import java.time.ZonedDateTime;
45
import java.util.ArrayList;
56
import java.util.List;
7+
import java.util.Optional;
8+
import javax.annotation.Nullable;
9+
import org.opentripplanner.updater.spi.UpdateError.UpdateErrorType;
10+
import org.opentripplanner.utils.lang.StringUtils;
611
import uk.org.siri.siri21.ArrivalBoardingActivityEnumeration;
712
import uk.org.siri.siri21.CallStatusEnumeration;
813
import uk.org.siri.siri21.DepartureBoardingActivityEnumeration;
@@ -43,7 +48,31 @@ static List<CallWrapper> of(EstimatedVehicleJourney estimatedVehicleJourney) {
4348
return List.copyOf(result);
4449
}
4550

51+
/**
52+
* Validate that all calls have a non-empty stop point ref and a non-null order.
53+
*/
54+
static Optional<UpdateErrorType> validateAll(List<CallWrapper> calls) {
55+
return calls.stream().map(CallWrapper::validate).flatMap(Optional::stream).findFirst();
56+
}
57+
58+
/**
59+
* Validate that the call has a non-empty stop point ref and a non-null order.
60+
*/
61+
default Optional<UpdateErrorType> validate() {
62+
if (StringUtils.hasNoValueOrNullAsString(getStopPointRef())) {
63+
return Optional.of(UpdateErrorType.EMPTY_STOP_POINT_REF);
64+
}
65+
if (getOrder() == null) {
66+
return Optional.of(UpdateErrorType.MISSING_CALL_ORDER);
67+
}
68+
return Optional.empty();
69+
}
70+
4671
String getStopPointRef();
72+
73+
@Nullable
74+
BigInteger getOrder();
75+
4776
Boolean isCancellation();
4877
Boolean isPredictionInaccurate();
4978
boolean isExtraCall();
@@ -73,6 +102,11 @@ public String getStopPointRef() {
73102
return call.getStopPointRef() != null ? call.getStopPointRef().getValue() : null;
74103
}
75104

105+
@Override
106+
public BigInteger getOrder() {
107+
return call.getOrder();
108+
}
109+
76110
@Override
77111
public Boolean isCancellation() {
78112
return call.isCancellation();
@@ -175,6 +209,11 @@ public String getStopPointRef() {
175209
return call.getStopPointRef() != null ? call.getStopPointRef().getValue() : null;
176210
}
177211

212+
@Override
213+
public BigInteger getOrder() {
214+
return call.getOrder();
215+
}
216+
178217
@Override
179218
public Boolean isCancellation() {
180219
return call.isCancellation();

application/src/main/java/org/opentripplanner/updater/trip/siri/SiriRealTimeTripUpdateAdapter.java

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package org.opentripplanner.updater.trip.siri;
22

33
import static java.lang.Boolean.TRUE;
4-
import static org.opentripplanner.updater.spi.UpdateError.UpdateErrorType.EMPTY_STOP_POINT_REF;
54
import static org.opentripplanner.updater.spi.UpdateError.UpdateErrorType.NOT_MONITORED;
65
import static org.opentripplanner.updater.spi.UpdateError.UpdateErrorType.NO_START_DATE;
76
import static org.opentripplanner.updater.spi.UpdateError.UpdateErrorType.TRIP_NOT_FOUND;
@@ -33,7 +32,6 @@
3332
import org.opentripplanner.updater.trip.UpdateIncrementality;
3433
import org.opentripplanner.updater.trip.patterncache.TripPatternCache;
3534
import org.opentripplanner.updater.trip.patterncache.TripPatternIdGenerator;
36-
import org.opentripplanner.utils.lang.StringUtils;
3735
import org.slf4j.Logger;
3836
import org.slf4j.LoggerFactory;
3937
import uk.org.siri.siri21.EstimatedTimetableDeliveryStructure;
@@ -133,10 +131,9 @@ private Result<UpdateSuccess, UpdateError> apply(
133131
EntityResolver entityResolver
134132
) {
135133
List<CallWrapper> callWrappers = CallWrapper.of(journey);
136-
for (var call : callWrappers) {
137-
if (StringUtils.hasNoValueOrNullAsString(call.getStopPointRef())) {
138-
return UpdateError.result(null, EMPTY_STOP_POINT_REF, journey.getDataSource());
139-
}
134+
var error = CallWrapper.validateAll(callWrappers);
135+
if (error.isPresent()) {
136+
return UpdateError.result(null, error.get(), journey.getDataSource());
140137
}
141138
SiriUpdateType siriUpdateType = null;
142139
try {

application/src/test/java/org/opentripplanner/updater/trip/siri/SiriEtBuilder.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,12 @@ public RecordedCallsBuilder withIsCancellation(boolean cancel) {
246246
return this;
247247
}
248248

249+
public RecordedCallsBuilder clearOrder() {
250+
var call = calls.getLast();
251+
call.setOrder(null);
252+
return this;
253+
}
254+
249255
public RecordedCallsBuilder addDestinationDisplay(String destinationDisplay) {
250256
var dd = new NaturalLanguageStringStructure();
251257
dd.setValue(destinationDisplay);
@@ -347,6 +353,12 @@ public EstimatedCallsBuilder withArrivalStopAssignment(
347353
return this;
348354
}
349355

356+
public EstimatedCallsBuilder clearOrder() {
357+
var call = calls.getLast();
358+
call.setOrder(null);
359+
return this;
360+
}
361+
350362
public EstimatedCallsBuilder addDestinationDisplay(String destinationDisplay) {
351363
var dd = new NaturalLanguageStringStructure();
352364
dd.setValue(destinationDisplay);

application/src/test/java/org/opentripplanner/updater/trip/siri/TestCall.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.opentripplanner.updater.trip.siri;
22

3+
import java.math.BigInteger;
34
import java.time.ZonedDateTime;
45
import java.util.List;
56
import uk.org.siri.siri21.ArrivalBoardingActivityEnumeration;
@@ -72,6 +73,11 @@ public String getStopPointRef() {
7273
return stopPointRef;
7374
}
7475

76+
@Override
77+
public BigInteger getOrder() {
78+
return null;
79+
}
80+
7581
@Override
7682
public Boolean isCancellation() {
7783
return cancellation;
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package org.opentripplanner.updater.trip.siri.moduletests.rejection;
2+
3+
import static org.opentripplanner.updater.spi.UpdateError.UpdateErrorType.MISSING_CALL_ORDER;
4+
import static org.opentripplanner.updater.spi.UpdateResultAssertions.assertFailure;
5+
6+
import org.junit.jupiter.api.Test;
7+
import org.opentripplanner.transit.model._data.TransitTestEnvironment;
8+
import org.opentripplanner.transit.model._data.TransitTestEnvironmentBuilder;
9+
import org.opentripplanner.transit.model._data.TripInput;
10+
import org.opentripplanner.transit.model.site.RegularStop;
11+
import org.opentripplanner.updater.trip.RealtimeTestConstants;
12+
import org.opentripplanner.updater.trip.SiriTestHelper;
13+
14+
class MissingCallOrderTest implements RealtimeTestConstants {
15+
16+
private final TransitTestEnvironmentBuilder ENV_BUILDER = TransitTestEnvironment.of();
17+
private final RegularStop STOP_A = ENV_BUILDER.stop(STOP_A_ID);
18+
private final RegularStop STOP_B = ENV_BUILDER.stop(STOP_B_ID);
19+
private final RegularStop STOP_C = ENV_BUILDER.stop(STOP_C_ID);
20+
21+
private final TripInput TRIP_INPUT = TripInput.of(TRIP_1_ID)
22+
.withWithTripOnServiceDate(TRIP_1_ID)
23+
.addStop(STOP_A, "0:00:10", "0:00:11")
24+
.addStop(STOP_B, "0:00:20", "0:00:21")
25+
.addStop(STOP_C, "0:00:40", "0:00:41");
26+
27+
@Test
28+
void rejectMissingOrderOnEstimatedCall() {
29+
var env = ENV_BUILDER.addTrip(TRIP_INPUT).build();
30+
var siri = SiriTestHelper.of(env);
31+
32+
var updates = siri
33+
.etBuilder()
34+
.withDatedVehicleJourneyRef(TRIP_1_ID)
35+
.withEstimatedCalls(builder ->
36+
builder
37+
.call(STOP_A)
38+
.departAimedExpected("00:00:11", "00:00:15")
39+
.call(STOP_B)
40+
.departAimedExpected("00:00:21", "00:00:25")
41+
.call(STOP_C)
42+
.arriveAimedExpected("00:00:40", "00:00:45")
43+
.clearOrder()
44+
)
45+
.buildEstimatedTimetableDeliveries();
46+
47+
var result = siri.applyEstimatedTimetable(updates);
48+
assertFailure(MISSING_CALL_ORDER, result);
49+
}
50+
51+
@Test
52+
void rejectMissingOrderOnRecordedCall() {
53+
var env = ENV_BUILDER.addTrip(TRIP_INPUT).build();
54+
var siri = SiriTestHelper.of(env);
55+
56+
var updates = siri
57+
.etBuilder()
58+
.withDatedVehicleJourneyRef(TRIP_1_ID)
59+
.withRecordedCalls(builder ->
60+
builder.call(STOP_A).departAimedActual("00:00:11", "00:00:15").clearOrder()
61+
)
62+
.withEstimatedCalls(builder ->
63+
builder
64+
.call(STOP_B)
65+
.departAimedExpected("00:00:21", "00:00:25")
66+
.call(STOP_C)
67+
.arriveAimedExpected("00:00:40", "00:00:45")
68+
)
69+
.buildEstimatedTimetableDeliveries();
70+
71+
var result = siri.applyEstimatedTimetable(updates);
72+
assertFailure(MISSING_CALL_ORDER, result);
73+
}
74+
}

0 commit comments

Comments
 (0)