diff --git a/src/main/java/de/stklcode/pubtrans/ura/UraClient.java b/src/main/java/de/stklcode/pubtrans/ura/UraClient.java index 605fa4c..d903f86 100644 --- a/src/main/java/de/stklcode/pubtrans/ura/UraClient.java +++ b/src/main/java/de/stklcode/pubtrans/ura/UraClient.java @@ -2,6 +2,7 @@ package de.stklcode.pubtrans.ura; import com.fasterxml.jackson.databind.ObjectMapper; import de.stklcode.pubtrans.ura.model.Stop; +import de.stklcode.pubtrans.ura.model.Trip; import java.io.BufferedReader; import java.io.IOException; @@ -9,6 +10,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** @@ -23,17 +25,34 @@ public class UraClient { private static final String FILTER_LINE = "LineID"; private static final String FILTER_STOP = "StopID"; - private static final String REQUEST_STOP_ID = "StopID"; - private static final String REQUEST_STOP_NAME = "StopPointName"; - private static final String REQUEST_STOP_STATE = "StopPointState"; - private static final String REQUEST_STOP_INDICATOR = "StopPointIndicator"; - private static final String REQUEST_GEOLOCATION = "Latitude,Longitude"; + private static final String PAR_STOP_ID = "StopID"; + private static final String PAR_STOP_NAME = "StopPointName"; + private static final String PAR_STOP_STATE = "StopPointState"; + private static final String PAR_STOP_INDICATOR = "StopPointIndicator"; + private static final String PAR_GEOLOCATION = "Latitude,Longitude"; + private static final String PAR_VISIT_NUMBER = "VisitNumber"; + private static final String PAR_LINE_ID = "LineID"; + private static final String PAR_LINE_NAME = "LineName"; + private static final String PAR_DIR_ID = "DirectionID"; + private static final String PAR_DEST_NAME = "DestinationName"; + private static final String PAR_DEST_TEXT = "DestinationText"; + private static final String PAR_VEHICLE_ID = "VehicleID"; + private static final String PAR_TRIP_ID = "TripID"; + private static final String PAR_ESTTIME = "EstimatedTime"; + + + private static final String[] REQUEST_STOP = {PAR_STOP_NAME, PAR_STOP_ID, PAR_STOP_INDICATOR, PAR_STOP_STATE, PAR_GEOLOCATION}; + private static final String[] REQUEST_TRIP = {PAR_STOP_NAME, PAR_STOP_ID, PAR_STOP_INDICATOR, PAR_STOP_STATE, PAR_GEOLOCATION, + PAR_VISIT_NUMBER, PAR_LINE_ID, PAR_LINE_NAME, PAR_DIR_ID, PAR_DEST_NAME, PAR_DEST_TEXT, PAR_VEHICLE_ID, PAR_TRIP_ID, PAR_ESTTIME}; private final String baseURL; private final String instantURL; private final String streamURL; private final ObjectMapper mapper; + private String[] stops; + private String[] lines; + /** * Constructor with base URL and default API paths. * @@ -57,6 +76,86 @@ public class UraClient { this.mapper = new ObjectMapper(); } + /** + * Builder pattern to request given stops. + * + * @param stops Stop IDs + * @return the client + */ + public UraClient forStops(final String...stops) { + this.stops = stops; + return this; + } + + /** + * Builder pattern to request given stops. + * + * @param lines line IDs + * @return the client + */ + public UraClient forLines(final String...lines) { + this.lines = lines; + return this; + } + + /** + * Get list of trips. + * If forStops() and/or forLines() has been called, those will be used as filter. + * + * @return list of trips + */ + public List getTrips() { + return getTrips(stops, lines, null); + } + + /** + * Get list of trips with limit. + * If forStops() and/or forLines() has been called, those will be used as filter. + * + * @return list of trips + */ + public List getTrips(final Integer limit) { + return getTrips(stops, lines, limit); + } + + /** + * Get list of trips for given stops and lines. + * + * @param stops the stops + * @param lines the lines + * @return list of trips + */ + public List getTrips(final String[] stops, final String[] lines) { + return getTrips(stops, lines, null); + } + + /** + * Get list of trips for given stops and lines with result limit. + * + * @param stops the stops + * @param lines the lines + * @param limit maximum number of results + * @return list of trips + */ + public List getTrips(final String[] stops, final String[] lines, final Integer limit) { + List trips = new ArrayList<>(); + try (InputStream is = requestInstant(REQUEST_TRIP, stops, lines); + BufferedReader br = new BufferedReader(new InputStreamReader(is))) { + String line; + boolean first = false; + while ((line = br.readLine()) != null) { + if (!first) { + first = true; + continue; + } + trips.add(new Trip(mapper.readValue(line, List.class))); + } + } catch (IOException e) { + e.printStackTrace(); + } + return trips; + } + /** * List available stops. * @@ -64,7 +163,7 @@ public class UraClient { */ public List listStops() { List stops = new ArrayList<>(); - try (InputStream is = requestInstant(REQUEST_STOP_NAME, REQUEST_STOP_ID, REQUEST_GEOLOCATION); + try (InputStream is = requestInstant(REQUEST_STOP, null, null); BufferedReader br = new BufferedReader(new InputStreamReader(is))) { String line; boolean first = false; @@ -88,8 +187,13 @@ public class UraClient { * @return Input stream of the URL * @throws IOException on errors */ - private InputStream requestInstant(String...returnList) throws IOException { - URL url = new URL(baseURL + instantURL + "?ReturnList=" + String.join(",", returnList)); + private InputStream requestInstant(String[] returnList, String[] stops, String[] lines) throws IOException { + String urlStr = baseURL + instantURL + "?ReturnList=" + String.join(",", returnList); + if (stops != null && stops.length > 0) + urlStr += "&" + FILTER_STOP + "=" + String.join(",", stops); + if (lines != null && lines.length > 0) + urlStr += "&" + FILTER_LINE + "=" + String.join(",", lines); + URL url = new URL(urlStr); return url.openStream(); } } diff --git a/src/main/java/de/stklcode/pubtrans/ura/model/Stop.java b/src/main/java/de/stklcode/pubtrans/ura/model/Stop.java index 6daa46f..71060b6 100644 --- a/src/main/java/de/stklcode/pubtrans/ura/model/Stop.java +++ b/src/main/java/de/stklcode/pubtrans/ura/model/Stop.java @@ -1,48 +1,58 @@ package de.stklcode.pubtrans.ura.model; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.databind.annotation.JsonAppend; - +import java.io.IOException; import java.util.List; -import java.util.StringJoiner; /** - * Created by stefan on 24.12.16. + * Entity for a single stop. + * + * @author Stefan Kalscheuer */ -@JsonIgnoreProperties(ignoreUnknown = true) public class Stop { private final String id; private final String name; + private final String indicator; + private final Integer state; private final Double latitude; private final Double longitude; - public Stop(String id, String name, Double latitude, Double longitude) { + public Stop(String id, String name, String indicator, Integer state, Double latitude, Double longitude) { this.id = id; this.name = name; + this.indicator = indicator; + this.state = state; this.latitude = latitude; this.longitude = longitude; } - public Stop(List raw) { + public Stop(List raw) throws IOException { + if (raw == null || raw.size() < 7) + throw new IOException("Invalid number of fields"); + if (raw.get(1) instanceof String) name = (String)raw.get(1); else - throw new UnsupportedOperationException("Field 1 not of expected Type String"); + throw new IOException("Field 1 not of expected type String, found " + raw.get(1).getClass().getSimpleName()); if (raw.get(2) instanceof String) id = (String)raw.get(2); else - throw new UnsupportedOperationException("Field 2 not of expected Type String"); - if (raw.get(3) instanceof Double) - latitude = (Double)raw.get(3); + throw new IOException("Field 2 not of expected type String, found " + raw.get(2).getClass().getSimpleName()); + if (raw.get(3) instanceof String) + indicator = (String)raw.get(3); else - throw new UnsupportedOperationException("Field 3 not of expected Type Double"); + throw new IOException("Field 3 not of expected type String, found " + raw.get(3).getClass().getSimpleName()); + if (raw.get(4) instanceof String) + state = (Integer)raw.get(4); + else + throw new IOException("Field 4 not of expected type Integer, found " + raw.get(4).getClass().getSimpleName()); + if (raw.get(5) instanceof Double) + latitude = (Double)raw.get(5); + else + throw new IOException("Field 5 not of expected type Double, found " + raw.get(5).getClass().getSimpleName()); if (raw.get(4) instanceof Double) - longitude = (Double)raw.get(4); + longitude = (Double)raw.get(6); else - throw new UnsupportedOperationException("Field 4 not of expected Type Double"); + throw new IOException("Field 6 not of expected type Double, found " + raw.get(6).getClass().getSimpleName()); } @@ -54,6 +64,14 @@ public class Stop { return name; } + public String getIndicator() { + return indicator; + } + + public Integer getState() { + return state; + } + public Double getLatitude() { return latitude; } diff --git a/src/main/java/de/stklcode/pubtrans/ura/model/Trip.java b/src/main/java/de/stklcode/pubtrans/ura/model/Trip.java new file mode 100644 index 0000000..9b2df24 --- /dev/null +++ b/src/main/java/de/stklcode/pubtrans/ura/model/Trip.java @@ -0,0 +1,85 @@ +package de.stklcode.pubtrans.ura.model; + +import java.io.IOException; +import java.util.List; + +/** + * Entity for a single trip. + * + * @author Stefan Kalscheuer + */ +public class Trip { + private final Stop stop; + private final String id; + private final Integer visitID; + private final String lineID; + private final String lineName; + private final Integer directionID; + private final String destinationName; + private final String destinationText; + private final Long estimatedTime; + private final String vehicleID; + + public Trip(String stopID, String stopName, String stopIndicator, Integer stopState, Double stopLatitude, Double stopLongitude, + Integer visitID, String lineID, String lineName, Integer directionID, String destinationName, String destinationText, String vehicleID, String tripID, Long estimatedTime) { + this(new Stop(stopID, stopName, stopIndicator, stopState, stopLatitude, stopLongitude), + visitID, lineID, lineName, directionID, destinationName, destinationText, vehicleID, tripID, estimatedTime); + } + + public Trip(Stop stop, Integer visitID, String lineID, String lineName, Integer directionID, String destinationName, String destinationText, String vehicleID, String tripID, Long estimatedTime) { + this.stop = stop; + this.visitID = visitID; + this.lineID = lineID; + this.lineName = lineName; + this.directionID = directionID; + this.destinationName = destinationName; + this.destinationText = destinationText; + this.vehicleID = vehicleID; + this.id = tripID; + this.estimatedTime = estimatedTime; + } + + public Trip(List raw) throws IOException { + if (raw == null || raw.size() < 16) + throw new IOException("Invalid number of fields"); + + stop = new Stop(raw); + + if (raw.get(7) instanceof Integer) + visitID = (Integer) raw.get(7); + else + throw new IOException("Field 7 not of expected type Integer, found " + raw.get(7).getClass().getSimpleName()); + if (raw.get(8) instanceof String) + lineID = (String)raw.get(8); + else + throw new IOException("Field 8 not of expected type String, found " + raw.get(8).getClass().getSimpleName()); + if (raw.get(9) instanceof String) + lineName = (String)raw.get(9); + else + throw new IOException("Field 9 not of expected type String, found " + raw.get(9).getClass().getSimpleName()); + if (raw.get(10) instanceof Integer) + directionID = (Integer)raw.get(10); + else + throw new IOException("Field 10 not of expected type Integer, found " + raw.get(10).getClass().getSimpleName()); + if (raw.get(11) instanceof String) + destinationName = (String)raw.get(11); + else + throw new IOException("Field 11 not of expected type String, found " + raw.get(11).getClass().getSimpleName()); + if (raw.get(12) instanceof String) + destinationText = (String)raw.get(12); + else + throw new IOException("Field 12 not of expected type String, found " + raw.get(12).getClass().getSimpleName()); + if (raw.get(13) instanceof String) + vehicleID = (String)raw.get(13); + else + throw new IOException("Field 13 not of expected type String, found " + raw.get(13).getClass().getSimpleName()); + if (raw.get(14) instanceof String) + id = (String)raw.get(14); + else + throw new IOException("Field 14 not of expected type String, found " + raw.get(14).getClass().getSimpleName()); + if (raw.get(15) instanceof Long) + estimatedTime = (Long)raw.get(15); + else + throw new IOException("Field 15 not of expected type Long, found " + raw.get(15).getClass().getSimpleName()); + } +}