Skip to content

Commit a867d3e

Browse files
authored
Merge pull request #150 from HSLdevcom/DT-2044
DT-2044
2 parents 02d625c + 1f39bf8 commit a867d3e

File tree

9 files changed

+223
-45
lines changed

9 files changed

+223
-45
lines changed

src/main/java/org/opentripplanner/index/GraphQlPlanner.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import java.util.function.Consumer;
99
import java.util.stream.Collectors;
1010

11-
import com.google.common.collect.ImmutableMap;
1211
import org.onebusaway.gtfs.model.AgencyAndId;
1312
import org.opentripplanner.api.common.Message;
1413
import org.opentripplanner.api.common.ParameterException;
@@ -22,16 +21,19 @@
2221
import org.opentripplanner.common.model.GenericLocation;
2322
import org.opentripplanner.routing.core.OptimizeType;
2423
import org.opentripplanner.routing.core.RoutingRequest;
24+
import org.opentripplanner.routing.core.ZoneIdSet;
2525
import org.opentripplanner.routing.graph.GraphIndex;
2626
import org.opentripplanner.routing.impl.GraphPathFinder;
2727
import org.opentripplanner.routing.spt.GraphPath;
2828
import org.opentripplanner.standalone.Router;
2929
import org.opentripplanner.util.ResourceBundleSingleton;
30-
31-
import graphql.schema.DataFetchingEnvironment;
3230
import org.slf4j.Logger;
3331
import org.slf4j.LoggerFactory;
3432

33+
import com.google.common.collect.ImmutableMap;
34+
35+
import graphql.schema.DataFetchingEnvironment;
36+
3537
public class GraphQlPlanner {
3638

3739
private static final Logger LOG = LoggerFactory.getLogger(GraphQlPlanner.class);
@@ -201,6 +203,15 @@ private RoutingRequest createRequest(DataFetchingEnvironment environment) {
201203
new QualifiedModeSet(environment.getArgument("modes")).applyToRoutingRequest(request);
202204
request.setModes(request.modes);
203205
}
206+
207+
if (hasArgument(environment, "ticketTypes")) {
208+
String ticketTypes = environment.getArgument("ticketTypes");
209+
request.setZoneIdSet(ZoneIdSet.create(index, ticketTypes));
210+
//TODO should we increase max walk distance?
211+
//request.setMaxWalkDistance(request.getMaxWalkDistance()*2);
212+
} else {
213+
request.setZoneIdSet(new ZoneIdSet());
214+
}
204215

205216
if (request.allowBikeRental && !hasArgument(environment, "bikeSpeed")) {
206217
//slower bike speed for bike sharing, based on empirical evidence from DC.

src/main/java/org/opentripplanner/index/IndexGraphQLSchema.java

Lines changed: 86 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,23 @@
11
package org.opentripplanner.index;
22

3-
import com.google.common.collect.ImmutableMap;
4-
import com.vividsolutions.jts.geom.Coordinate;
5-
import com.vividsolutions.jts.geom.Envelope;
6-
import com.vividsolutions.jts.geom.LineString;
7-
import graphql.Scalars;
8-
import graphql.relay.Relay;
9-
import graphql.relay.SimpleListConnection;
10-
import graphql.schema.DataFetcher;
11-
import graphql.schema.DataFetchingEnvironment;
12-
import graphql.schema.DataFetchingEnvironmentImpl;
13-
import graphql.schema.GraphQLArgument;
14-
import graphql.schema.GraphQLEnumType;
15-
import graphql.schema.GraphQLFieldDefinition;
16-
import graphql.schema.GraphQLInputObjectField;
17-
import graphql.schema.GraphQLInputObjectType;
18-
import graphql.schema.GraphQLInterfaceType;
19-
import graphql.schema.GraphQLList;
20-
import graphql.schema.GraphQLNonNull;
21-
import graphql.schema.GraphQLObjectType;
22-
import graphql.schema.GraphQLOutputType;
23-
import graphql.schema.GraphQLSchema;
24-
import graphql.schema.GraphQLType;
25-
import graphql.schema.GraphQLTypeReference;
26-
import graphql.schema.PropertyDataFetcher;
27-
import graphql.schema.TypeResolver;
3+
import static java.util.Collections.emptyList;
4+
5+
import java.text.ParseException;
6+
import java.util.ArrayList;
7+
import java.util.Arrays;
8+
import java.util.BitSet;
9+
import java.util.Collection;
10+
import java.util.Collections;
11+
import java.util.Comparator;
12+
import java.util.HashMap;
13+
import java.util.HashSet;
14+
import java.util.List;
15+
import java.util.Map;
16+
import java.util.Objects;
17+
import java.util.Set;
18+
import java.util.stream.Collectors;
19+
import java.util.stream.Stream;
20+
2821
import org.onebusaway.gtfs.model.Agency;
2922
import org.onebusaway.gtfs.model.AgencyAndId;
3023
import org.onebusaway.gtfs.model.Route;
@@ -55,6 +48,7 @@
5548
import org.opentripplanner.routing.core.Money;
5649
import org.opentripplanner.routing.core.OptimizeType;
5750
import org.opentripplanner.routing.core.ServiceDay;
51+
import org.opentripplanner.routing.core.TicketType;
5852
import org.opentripplanner.routing.core.TraverseMode;
5953
import org.opentripplanner.routing.edgetype.SimpleTransfer;
6054
import org.opentripplanner.routing.edgetype.Timetable;
@@ -71,14 +65,38 @@
7165
import org.opentripplanner.util.TranslatedString;
7266
import org.opentripplanner.util.model.EncodedPolylineBean;
7367

74-
import java.text.ParseException;
75-
import java.util.*;
76-
import java.util.stream.Collectors;
77-
import java.util.stream.Stream;
68+
import com.google.common.collect.ImmutableMap;
69+
import com.vividsolutions.jts.geom.Coordinate;
70+
import com.vividsolutions.jts.geom.Envelope;
71+
import com.vividsolutions.jts.geom.LineString;
7872

79-
import static java.util.Collections.emptyList;
73+
import graphql.Scalars;
74+
import graphql.relay.Relay;
75+
import graphql.relay.SimpleListConnection;
76+
import graphql.schema.DataFetcher;
77+
import graphql.schema.DataFetchingEnvironment;
78+
import graphql.schema.DataFetchingEnvironmentImpl;
79+
import graphql.schema.GraphQLArgument;
80+
import graphql.schema.GraphQLEnumType;
81+
import graphql.schema.GraphQLFieldDefinition;
82+
import graphql.schema.GraphQLInputObjectField;
83+
import graphql.schema.GraphQLInputObjectType;
84+
import graphql.schema.GraphQLInterfaceType;
85+
import graphql.schema.GraphQLList;
86+
import graphql.schema.GraphQLNonNull;
87+
import graphql.schema.GraphQLObjectType;
88+
import graphql.schema.GraphQLOutputType;
89+
import graphql.schema.GraphQLSchema;
90+
import graphql.schema.GraphQLType;
91+
import graphql.schema.GraphQLTypeReference;
92+
import graphql.schema.PropertyDataFetcher;
93+
import graphql.schema.TypeResolver;
8094

8195
public class IndexGraphQLSchema {
96+
97+
public static String experimental(String message) {
98+
return String.format("!!This api is experimental and might change without further notice!!\n %s", message);
99+
}
82100

83101
public static GraphQLEnumType locationTypeEnum = GraphQLEnumType.newEnum()
84102
.name("LocationType")
@@ -168,6 +186,8 @@ public class IndexGraphQLSchema {
168186
private final GtfsRealtimeFuzzyTripMatcher fuzzyTripMatcher;
169187

170188
public GraphQLOutputType agencyType = new GraphQLTypeReference("Agency");
189+
190+
public GraphQLOutputType ticketType = new GraphQLTypeReference("TicketType");
171191

172192
public GraphQLOutputType alertType = new GraphQLTypeReference("Alert");
173193

@@ -305,16 +325,6 @@ private Agency getAgency(GraphIndex index, String agencyId) {
305325
return null;
306326
}
307327

308-
private List<Agency> getAllAgencies(GraphIndex index) {
309-
//xxx what if there are duplciate agency ids?
310-
//now we return the first
311-
ArrayList<Agency> agencies = new ArrayList<Agency>();
312-
for (Map<String, Agency> feedAgencies : index.agenciesForFeedId.values()) {
313-
agencies.addAll(feedAgencies.values());
314-
}
315-
return agencies;
316-
}
317-
318328
@SuppressWarnings("unchecked")
319329
public IndexGraphQLSchema(GraphIndex index) {
320330
createPlanType(index);
@@ -635,6 +645,11 @@ public IndexGraphQLSchema(GraphIndex index) {
635645
.description("Locale for returned text")
636646
.type(Scalars.GraphQLString)
637647
.build())
648+
.argument(GraphQLArgument.newArgument()
649+
.name("ticketTypes")
650+
.description("Allowed ticket types")
651+
.type(Scalars.GraphQLString)
652+
.build())
638653
.dataFetcher(environment -> new GraphQlPlanner(index).plan(environment))
639654
.build();
640655

@@ -1822,6 +1837,30 @@ public IndexGraphQLSchema(GraphIndex index) {
18221837
.build())
18231838
.build();
18241839

1840+
ticketType = GraphQLObjectType.newObject()
1841+
.name("TicketType")
1842+
.description(experimental("Describes ticket type"))
1843+
.withInterface(nodeInterface)
1844+
.field(GraphQLFieldDefinition.newFieldDefinition()
1845+
.name("id")
1846+
.type(new GraphQLNonNull(Scalars.GraphQLID))
1847+
.dataFetcher(environment -> relay
1848+
.toGlobalId(ticketType.getName(), ((TicketType) environment.getSource()).getId()))
1849+
.build())
1850+
.field(GraphQLFieldDefinition.newFieldDefinition()
1851+
.name("fareId")
1852+
.type(new GraphQLNonNull(Scalars.GraphQLID))
1853+
.dataFetcher(environment -> ((TicketType) environment.getSource()).getId())
1854+
.build())
1855+
.field(GraphQLFieldDefinition.newFieldDefinition()
1856+
.name("price")
1857+
.type(Scalars.GraphQLFloat)
1858+
.dataFetcher(environment -> ((TicketType) environment.getSource()).getPrice())
1859+
.build()
1860+
)
1861+
.build();
1862+
1863+
18251864
carParkType = GraphQLObjectType.newObject()
18261865
.name("CarPark")
18271866
.withInterface(nodeInterface)
@@ -1979,6 +2018,13 @@ private Object getObject(String idString) {
19792018
.type(new GraphQLList(agencyType))
19802019
.dataFetcher(environment -> new ArrayList<>(index.getAllAgencies()))
19812020
.build())
2021+
.field(GraphQLFieldDefinition.newFieldDefinition()
2022+
.name("ticketTypes")
2023+
.description(experimental("Return list of available ticket types."))
2024+
.type(new GraphQLList(ticketType))
2025+
.dataFetcher(environment -> new ArrayList<>(index.getAllTicketTypes()))
2026+
.build()
2027+
)
19822028
.field(GraphQLFieldDefinition.newFieldDefinition()
19832029
.name("agency")
19842030
.description("Get a single agency based on agency ID")

src/main/java/org/opentripplanner/routing/core/FareRuleSet.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ public class FareRuleSet implements Serializable {
2929
private Set<AgencyAndId> routes;
3030
private Set<P2<String>> originDestinations;
3131
private Set<String> contains;
32+
public Set<String> getContains() {
33+
return contains;
34+
}
35+
3236
private FareAttribute fareAttribute;
3337
private Set<AgencyAndId> trips;
3438

src/main/java/org/opentripplanner/routing/core/RoutingRequest.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ the License, or (at your option) any later version.
3636
import org.slf4j.LoggerFactory;
3737

3838
import java.io.Serializable;
39+
import java.time.ZoneId;
3940
import java.util.ArrayList;
4041
import java.util.Arrays;
4142
import java.util.Date;
@@ -151,6 +152,8 @@ public class RoutingRequest implements Cloneable, Serializable {
151152

152153
public double carSpeed;
153154

155+
private ZoneIdSet zones = new ZoneIdSet(null);
156+
154157
public Locale locale = new Locale("en", "US");
155158

156159
/**
@@ -1294,4 +1297,16 @@ public void canSplitEdge(StreetEdge edge) {
12941297
}
12951298

12961299
}
1300+
1301+
/**
1302+
* Set allowed fare zones
1303+
* @param split
1304+
*/
1305+
public void setZoneIdSet(ZoneIdSet zones) {
1306+
this.zones = zones;
1307+
}
1308+
1309+
public ZoneIdSet getZoneIdSet() {
1310+
return zones;
1311+
}
12971312
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package org.opentripplanner.routing.core;
2+
3+
public class TicketType {
4+
FareRuleSet rs;
5+
6+
public TicketType(FareRuleSet rs) {
7+
this.rs = rs;
8+
}
9+
10+
public String getId() {
11+
return rs.getFareAttribute().getId().toString();
12+
}
13+
14+
public float getPrice() {
15+
return rs.getFareAttribute().getPrice();
16+
}
17+
18+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package org.opentripplanner.routing.core;
2+
3+
import java.util.Arrays;
4+
import java.util.Set;
5+
import java.util.stream.Collectors;
6+
7+
import org.opentripplanner.routing.graph.GraphIndex;
8+
9+
import com.google.common.collect.Sets;
10+
11+
public class ZoneIdSet {
12+
13+
private final Set<String> zones;
14+
15+
public ZoneIdSet(Set<String> zones) {
16+
this.zones = zones;
17+
}
18+
19+
public ZoneIdSet() {
20+
this.zones = null;
21+
}
22+
23+
public boolean isAllowed(String zone) {
24+
return zones == null || zones.contains(zone);
25+
}
26+
27+
public static final ZoneIdSet create(GraphIndex index, String ticketIds) {
28+
if (ticketIds != null) {
29+
Set<String> ticketTypes = Arrays.asList(ticketIds.split(",")).stream().map(String::trim)
30+
.collect(Collectors.toSet());
31+
Set<String> zones = Sets.newHashSet();
32+
for (TicketType tt : index.getAllTicketTypes()) {
33+
if (ticketTypes.contains(tt.rs.getFareAttribute().getId().toString())) {
34+
zones.addAll(tt.rs.getContains());
35+
}
36+
}
37+
return new ZoneIdSet(zones);
38+
}
39+
return new ZoneIdSet();
40+
}
41+
42+
@Override
43+
public String toString() {
44+
return zones == null ? "All zones allowed" : zones.toString();
45+
}
46+
}

src/main/java/org/opentripplanner/routing/edgetype/TransitBoardAlight.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ public State traverse(State state0) {
136136
public State traverse(State s0, long arrivalTimeAtStop) {
137137
RoutingContext rctx = s0.getContext();
138138
RoutingRequest options = s0.getOptions();
139+
if(!s0.getOptions().getZoneIdSet().isAllowed(getStop().getZoneId())) {
140+
return null;
141+
}
139142

140143
// Forbid taking shortcuts composed of two board-alight edges in a row. Also avoids spurious leg transitions.
141144
if (s0.backEdge instanceof TransitBoardAlight) {
@@ -155,7 +158,7 @@ public State traverse(State s0, long arrivalTimeAtStop) {
155158
boolean leavingTransit =
156159
( boarding && options.arriveBy) ||
157160
(!boarding && !options.arriveBy);
158-
161+
159162
/* TODO pull on/off transit out into two functions. */
160163
if (leavingTransit) {
161164
/* We are leaving transit, not as much to do. */
@@ -164,7 +167,9 @@ public State traverse(State s0, long arrivalTimeAtStop) {
164167
if (s0.getBackEdge() instanceof TransitBoardAlight) {
165168
return null;
166169
}
170+
167171
StateEditor s1 = s0.edit(this);
172+
168173
s1.setTripId(null);
169174
s1.setLastAlightedTimeSeconds(s0.getTimeSeconds());
170175
// Store the stop we are alighting at, for computing stop-to-stop transfer times,
@@ -370,6 +375,10 @@ private Stop getStop() {
370375

371376
public State optimisticTraverse(State state0) {
372377
StateEditor s1 = state0.edit(this);
378+
379+
if(!state0.getOptions().getZoneIdSet().isAllowed(getStop().getZoneId())) {
380+
return null;
381+
}
373382
// no cost (see patternalight)
374383
s1.setBackMode(getMode());
375384
return s1.makeState();

0 commit comments

Comments
 (0)