aboutsummaryrefslogtreecommitdiff
path: root/gtfs-realtime-book/ch-06-consuming-service-alerts.md
blob: 98691734c4896e5ad5dcd66f1aeff36559327876 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
## 6. Consuming Service Alerts

The previous chapter introduced you to Protocol Buffers and showed you
how load a remote GTFS-realtime feed into your Java project. This
chapter will show you how to read the data from each of the three entity
types (service alerts, vehicle positions and trip updates).

The previous chapter also showed you how to loop over all entities in a
feed using `getEntityList()`. Each entity contains either a service
alert, a vehicle position or a trip update.

Once you have verified that a `FeedEntity` element contains an alert,
you can retrieve the corresponding `Alert` object using
`getAlert()`.

```java
for (FeedEntity entity : fm.getEntityList()) {
	if (entity.hasAlert()) {
		Alert alert = entity.getAlert();

		processAlert(alert);
	}
}
```

You can then access the specific properties of a service alert using the
returned object.

### Cause & Effect

For example, to retrieve the cause value for the alert, you would first
check for its presence with `hasCause()` then retrieve the value using
`getCause()`.

```java
public void processAlert(Alert alert) {
	if (alert.hasCause()) {
		Cause cause = alert.getCause();

		// ...
	}

	// ...
}
```

The `Cause` object is an enumerator, meaning it has a finite number of
possible values. To determine which value the object corresponds to,
call `getNumber()` to compare it to the possible values.

```java
switch (cause.getNumber()) {
	case Cause.ACCIDENT_VALUE:
		// ...

	case Cause.MEDICAL_EMERGENCY_VALUE:
		// ...
}
```

Note: There are other possible cause values to include in the switch
statement; these have been omitted here as they are all covered in the
specification earlier in this book.

The `Effect` field works in the same way. The difference is that the
possible list of values to compare against is different.

```java
if (alert.hasEffect()) {
	Effect effect = alert.getEffect();

	switch (effect.getNumber()) {
	case Effect.DETOUR_VALUE:
		// ...

	case Effect.SIGNIFICANT_DELAYS_VALUE:
		// ...
	}
}
```

### Title, Description and URL

Each of these fields are of type `TranslatedString`. A
`TranslatedString` may contain multiple `Translation` objects, so
when processing these fields you must loop over the available
translations.

For example, to loop over the available translations for the header text
you iterate over **getTranslationList()**.

```java
if (alert.hasHeaderText()) {
	TranslatedString header = alert.getHeaderText();

	for (Translation translation : header.getTranslationList()) {
		// Process the translation here

	}
}
```

***Note:** To access the description you would use `hasDescription()` and
`getDescription()`, while to access the URL you would use `hasUrl()` and
`getUrl()`.*

Alternatively, you can use `getTranslationCount()` and
`getTranslation()` to retrieve each of the available translations.

```java
for (int i = 0; i < header.getTranslationCount(); i++) {
	Translation translation = header.getTranslation(i);

	// Process the translation here
}
```

A `Translation` object is made up of text and optionally, its
associated language. When dealing with the URL field, the text retrieved
from `getText()` contains a full URL.

```java
if (translation.hasLanguage()) {
	String language = translation.getLanguage();

	if (language.equals("fr")) {
		// Do something for French language
	}
	else {
		// All other languages
	}
}

if (translation.hasText()) {
	String text = translation.getText();

	// Do something with the text
}
```

***Note:** Most GTFS-realtime feeds only specify text in a single
language, and therefore do not include the language value.*

### Active Period

A service alert may contain zero or more time ranges, each of which
specify the dates and times the alert is active for. If none are
specified then the alert is active as long as it exists within the feed.

You can access each of the `TimeRange` objects using either of the
following methods:

```java
for (TimeRange timeRange : alert.getActivePeriodList()) {
	// ...
}

for (int i = 0; i < alert.getActivePeriodCount(); i++) {
	TimeRange timeRange = alert.getActivePeriod(i);

	// ...
}
```

A `TimeRange` can have either a start or finish date, or it may
contain both. In Java, you can turn each of these dates into a
`java.util.Date` object as shown below.

```java
if (timeRange.hasStart()) {
	Date start = new Date(timeRange.getStart() * 1000);

	// ...
}

if (timeRange.hasEnd()) {
	Date end = new Date(timeRange.getEnd() * 1000);

	// ...
}
```

***Note:** The date value is multiplied by 1,000 because the date in the
GTFS-realtime is represented by the number of seconds since January 1,
1970, while `java.util.Date` is instantiated using the number of
milliseconds since the same date.*

### Affected Entities

A service alert may contain zero or more affected entities, each of
which describes a route, stop, agency, trip or route type. You can
access these entities using either of the following methods:

```
for (EntitySelector entity : alert.getInformedEntityList()) {

}

for (int i = 0; i < alert.getInformedEntityCount(); i++) {
	EntitySelector entity = alert.getInformedEntity(i);

}
```

There are a number of properties available in the `EntitySelector`
object, each of which can be used to match the entity to the
corresponding GTFS feed.

For example, if the `EntitySelector` object has a route ID value, then
you should be able to locate the route in the corresponding GTFS feed's
`routes.txt` file.

The properties can be accessed as follows:

```java
if (entity.hasAgencyId()) {
	String agencyId = entity.getAgencyId();

}

if (entity.hasRouteId()) {
	String routeId = entity.getRouteId();

}

if (entity.hasRouteType()) {
	int routeType = entity.getRouteType();

}

if (entity.hasStopId()) {
	String stopId = entity.getStopId();

}
```

The route type value is an Integer and if present must correspond either
to the standard GTFS route type values, or to the extended route type
values.

The other entity information that can be contained in `EntitySelector`
is trip information. You can access the trip properties as follows:

```java
if (entity.hasTrip()) {
	TripDescriptor trip = entity.getTrip();

	if (trip.hasTripId()) {
		String tripId = trip.getTripId();

	}

	if (trip.hasRouteId()) {
		String routeId = trip.getRouteId();
		
	}

	if (trip.hasStartDate()) {
		String startDate = trip.getStartDate();

	}

	if (trip.hasStartTime()) {
		String startTime = trip.getStartTime();

	}

	if (trip.hasScheduleRelationship()) {
		ScheduleRelationship sr = trip.getScheduleRelationship();

	}
}
```

You can test the `ScheduleRelationship` value by comparing the
`getNumber()` value to one of the available constants, as follows.

```java
if (entity.hasTrip()) {
	// ...

	if (trip.hasScheduleRelationship()) {

		ScheduleRelationship sr = trip.getScheduleRelationship();

		switch (sr.getNumber()) {
			case ScheduleRelationship.ADDED_VALUE:
				// ...
				break;

			case ScheduleRelationship.CANCELED_VALUE:
				// ...
				break;

			case ScheduleRelationship.SCHEDULED_VALUE:
				// ...
				break;

			case ScheduleRelationship.UNSCHEDULED_VALUE:
				// ...
				break;
		}
	}
}
```