1
1
package com .conveyal .gtfs .loader ;
2
2
3
+ import com .conveyal .gtfs .GTFSFeed ;
4
+ import com .conveyal .gtfs .model .Calendar ;
5
+ import com .conveyal .gtfs .model .CalendarDate ;
3
6
import com .conveyal .gtfs .model .Entity ;
7
+ import com .conveyal .gtfs .model .ScheduleException ;
8
+ import com .conveyal .gtfs .model .Service ;
4
9
import org .apache .commons .dbutils .DbUtils ;
5
10
import org .postgresql .copy .CopyManager ;
6
11
import org .postgresql .core .BaseConnection ;
16
21
import java .io .OutputStream ;
17
22
import java .sql .Connection ;
18
23
import java .sql .SQLException ;
24
+ import java .time .LocalDate ;
19
25
import java .util .zip .ZipEntry ;
20
26
import java .util .zip .ZipOutputStream ;
21
27
@@ -27,18 +33,19 @@ public class JdbcGtfsExporter {
27
33
28
34
private final String outFile ;
29
35
private final DataSource dataSource ;
36
+ private final boolean fromEditor ;
30
37
31
38
// These fields will be filled in once feed snapshot begins.
32
39
private Connection connection ;
33
- private String tablePrefix ;
34
40
private ZipOutputStream zipOutputStream ;
35
41
// The reference feed ID (namespace) to copy.
36
42
private final String feedIdToExport ;
37
43
38
- public JdbcGtfsExporter (String feedId , String outFile , DataSource dataSource ) {
44
+ public JdbcGtfsExporter (String feedId , String outFile , DataSource dataSource , boolean fromEditor ) {
39
45
this .feedIdToExport = feedId ;
40
46
this .outFile = outFile ;
41
47
this .dataSource = dataSource ;
48
+ this .fromEditor = fromEditor ;
42
49
}
43
50
44
51
/**
@@ -62,20 +69,68 @@ public FeedLoadResult exportTables() {
62
69
connection = dataSource .getConnection ();
63
70
// Include the dot separator in the table prefix.
64
71
// This allows everything to work even when there's no prefix.
65
- this .tablePrefix += "." ;
66
72
// Export each table in turn (by placing entry in zip output stream).
67
73
// FIXME: NO non-fatal exception errors are being captured during copy operations.
68
74
result .agency = export (Table .AGENCY );
69
75
result .calendar = export (Table .CALENDAR );
70
- result .calendarDates = export (Table .CALENDAR_DATES );
76
+ if (fromEditor ) {
77
+ GTFSFeed feed = new GTFSFeed ();
78
+ // Export schedule exceptions in place of calendar dates if exporting from the GTFS Editor.
79
+ // FIXME: The below table readers should probably just share a connection with the exporter.
80
+ JDBCTableReader <ScheduleException > exceptionsReader =
81
+ new JDBCTableReader (Table .SCHEDULE_EXCEPTIONS , dataSource , feedIdToExport + "." ,
82
+ EntityPopulator .SCHEDULE_EXCEPTION );
83
+ JDBCTableReader <Calendar > calendarsReader =
84
+ new JDBCTableReader (Table .CALENDAR , dataSource , feedIdToExport + "." ,
85
+ EntityPopulator .CALENDAR );
86
+ Iterable <Calendar > calendars = calendarsReader .getAll ();
87
+ for (Calendar cal : calendars ) {
88
+ LOG .info ("Iterating over calendar {}" , cal .service_id );
89
+ Service service = new Service (cal .service_id );
90
+ service .calendar = cal ;
91
+ Iterable <ScheduleException > exceptions = exceptionsReader .getAll ();
92
+ for (ScheduleException ex : exceptions ) {
93
+ LOG .info ("Adding exception {} for calendar {}" , ex .name , cal .service_id );
94
+ if (ex .equals (ScheduleException .ExemplarServiceDescriptor .SWAP ) &&
95
+ !ex .addedService .contains (cal .service_id ) && !ex .removedService .contains (cal .service_id ))
96
+ // skip swap exception if cal is not referenced by added or removed service
97
+ // this is not technically necessary, but the output is cleaner/more intelligible
98
+ continue ;
99
+
100
+ for (LocalDate date : ex .dates ) {
101
+ if (date .isBefore (cal .start_date ) || date .isAfter (cal .end_date ))
102
+ // no need to write dates that do not apply
103
+ continue ;
104
+
105
+ CalendarDate calendarDate = new CalendarDate ();
106
+ calendarDate .date = date ;
107
+ calendarDate .service_id = cal .service_id ;
108
+ calendarDate .exception_type = ex .serviceRunsOn (cal ) ? 1 : 2 ;
109
+
110
+ if (service .calendar_dates .containsKey (date ))
111
+ throw new IllegalArgumentException ("Duplicate schedule exceptions on " + date .toString ());
112
+
113
+ service .calendar_dates .put (date , calendarDate );
114
+ }
115
+ }
116
+ feed .services .put (cal .service_id , service );
117
+ }
118
+ LOG .info ("Writing calendar dates from schedule exceptions" );
119
+ new CalendarDate .Writer (feed ).writeTable (zipOutputStream );
120
+ } else {
121
+ // Otherwise, simply export the calendar dates as they were loaded in.
122
+ result .calendarDates = export (Table .CALENDAR_DATES );
123
+ }
71
124
result .fareAttributes = export (Table .FARE_ATTRIBUTES );
72
125
result .fareRules = export (Table .FARE_RULES );
73
126
result .feedInfo = export (Table .FEED_INFO );
74
127
result .frequencies = export (Table .FREQUENCIES );
75
128
result .routes = export (Table .ROUTES );
76
129
// FIXME: Find some place to store errors encountered on export for patterns and pattern stops.
77
- export (Table .PATTERNS );
78
- export (Table .PATTERN_STOP );
130
+ // FIXME: Is there a need to export patterns or pattern stops? Should these be iterated over to ensure that
131
+ // frequency-based pattern travel times match stop time arrivals/departures?
132
+ // export(Table.PATTERNS);
133
+ // export(Table.PATTERN_STOP);
79
134
result .shapes = export (Table .SHAPES );
80
135
result .stops = export (Table .STOPS );
81
136
result .stopTimes = export (Table .STOP_TIMES );
@@ -103,7 +158,7 @@ private TableLoadResult export (Table table) {
103
158
TableLoadResult tableLoadResult = new TableLoadResult ();
104
159
try {
105
160
// Use the Postgres text load format if we're connected to that DBMS.
106
- boolean postgresText = ( connection .getMetaData ().getDatabaseProductName ().equals ("PostgreSQL" ) );
161
+ boolean postgresText = connection .getMetaData ().getDatabaseProductName ().equals ("PostgreSQL" );
107
162
108
163
if (postgresText ) {
109
164
// Create entry for table
@@ -133,8 +188,6 @@ private TableLoadResult export (Table table) {
133
188
}
134
189
tableLoadResult .fatalException = e .getMessage ();
135
190
LOG .error ("Exception while exporting tables" , e );
136
- } catch (FileNotFoundException e ) {
137
- e .printStackTrace ();
138
191
} catch (IOException e ) {
139
192
e .printStackTrace ();
140
193
}
0 commit comments