forked from opentripplanner/OpenTripPlanner
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathNetexBundle.java
180 lines (154 loc) · 5.95 KB
/
NetexBundle.java
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
package org.opentripplanner.netex;
import java.io.Closeable;
import java.io.IOException;
import java.util.List;
import java.util.Set;
import javax.xml.bind.JAXBException;
import org.opentripplanner.datastore.api.CompositeDataSource;
import org.opentripplanner.datastore.api.DataSource;
import org.opentripplanner.graph_builder.DataImportIssueStore;
import org.opentripplanner.model.impl.OtpTransitServiceBuilder;
import org.opentripplanner.netex.index.NetexEntityIndex;
import org.opentripplanner.netex.loader.GroupEntries;
import org.opentripplanner.netex.loader.NetexDataSourceHierarchy;
import org.opentripplanner.netex.loader.NetexXmlParser;
import org.opentripplanner.netex.loader.parser.NetexDocumentParser;
import org.opentripplanner.netex.mapping.NetexMapper;
import org.opentripplanner.netex.validation.Validator;
import org.opentripplanner.standalone.config.NetexConfig;
import org.opentripplanner.transit.model.framework.Deduplicator;
import org.rutebanken.netex.model.PublicationDeliveryStructure;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Loads/reads a NeTEx bundle of a data source(zip file/directory/cloud storage) and maps it into
* the OTP internal transit model.
* <p>
* The NeTEx loader will use a file naming convention to load files in a particular order and
* keeping an index of entities to enable linking. The convention is documented here {@link
* NetexConfig#sharedFilePattern} and here {@link NetexDataSourceHierarchy}.
* <p>
* This class is also responsible for logging progress and exception handling.
*/
public class NetexBundle implements Closeable {
private static final Logger LOG = LoggerFactory.getLogger(NetexBundle.class);
private final CompositeDataSource source;
private final NetexDataSourceHierarchy hierarchy;
private final String netexFeedId;
private final Set<String> ferryIdsNotAllowedForBicycle;
private final double maxStopToShapeSnapDistance;
/** The NeTEx entities loaded from the input files and passed on to the mapper. */
private NetexEntityIndex index = new NetexEntityIndex();
/** Report errors to issue store */
private DataImportIssueStore issueStore;
/** maps the NeTEx XML document to OTP transit model. */
private NetexMapper mapper;
private NetexXmlParser xmlParser;
public NetexBundle(
String netexFeedId,
CompositeDataSource source,
NetexDataSourceHierarchy hierarchy,
Set<String> ferryIdsNotAllowedForBicycle,
double maxStopToShapeSnapDistance
) {
this.netexFeedId = netexFeedId;
this.source = source;
this.hierarchy = hierarchy;
this.ferryIdsNotAllowedForBicycle = ferryIdsNotAllowedForBicycle;
this.maxStopToShapeSnapDistance = maxStopToShapeSnapDistance;
}
/** load the bundle, map it to the OTP transit model and return */
public OtpTransitServiceBuilder loadBundle(
Deduplicator deduplicator,
DataImportIssueStore issueStore
) {
LOG.info("Reading {}", hierarchy.description());
this.issueStore = issueStore;
// Store result in a mutable OTP Transit Model
OtpTransitServiceBuilder transitBuilder = new OtpTransitServiceBuilder();
// init parser and mapper
xmlParser = new NetexXmlParser();
mapper =
new NetexMapper(
transitBuilder,
netexFeedId,
deduplicator,
issueStore,
ferryIdsNotAllowedForBicycle,
maxStopToShapeSnapDistance
);
// Load data
loadFileEntries();
return transitBuilder;
}
public void checkInputs() {
if (!source.exists()) {
throw new RuntimeException("NeTEx " + source.path() + " does not exist.");
}
}
/* private methods */
@Override
public void close() throws IOException {
source.close();
}
/** Load all files entries in the bundle */
private void loadFileEntries() {
// Load global shared files
loadFilesThenMapToOtpTransitModel("shared file", hierarchy.sharedEntries());
for (GroupEntries group : hierarchy.groups()) {
LOG.info("reading group {}", group.name());
scopeInputData(() -> {
// Load shared group files
loadFilesThenMapToOtpTransitModel("shared group file", group.sharedEntries());
for (DataSource entry : group.independentEntries()) {
scopeInputData(() -> {
// Load each independent file in group
loadFilesThenMapToOtpTransitModel("group file", List.of(entry));
});
}
});
}
mapper.finnishUp();
NetexDocumentParser.finnishUp();
}
/**
* make a new index and pushes it on the index stack, before executing the task and at the end pop
* of the index.
*/
private void scopeInputData(Runnable task) {
index = index.push();
mapper = mapper.push();
task.run();
mapper = mapper.pop();
index = index.pop();
}
/**
* Load a set of files and map the entries to OTP Transit model after the loading is complete. It
* is important to do this in 2 steps to be able to link references. An attempt to map each entry,
* when read, would lead to missing references, since the order entries are read is not enforced
* in any way.
*/
private void loadFilesThenMapToOtpTransitModel(
String fileDescription,
Iterable<DataSource> entries
) {
for (DataSource entry : entries) {
// Load entry and store it in the index
loadSingeFileEntry(fileDescription, entry);
}
// Validate input data, and remove invalid data
Validator.validate(index, issueStore);
// map current NeTEx objects into the OTP Transit Model
mapper.mapNetexToOtp(index.readOnlyView());
}
/** Load a single entry and store it in the index for later */
private void loadSingeFileEntry(String fileDescription, DataSource entry) {
try {
LOG.info("reading entity {}: {}", fileDescription, entry.name());
PublicationDeliveryStructure doc = xmlParser.parseXmlDoc(entry.asInputStream());
NetexDocumentParser.parseAndPopulateIndex(index, doc);
} catch (JAXBException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}