Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Addressing review feedback: Implementing changes #6

Merged
merged 8 commits into from
May 6, 2024
25 changes: 25 additions & 0 deletions .idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/codeStyles/codeStyleConfig.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

36 changes: 24 additions & 12 deletions src/main/java/ch/naviqore/gtfs/schedule/GtfsScheduleFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,30 @@
*/
@RequiredArgsConstructor
@Getter
public enum GtfsScheduleFile {
AGENCY("agency.txt"),
CALENDAR("calendar.txt"),
CALENDAR_DATES("calendar_dates.txt"),
// FARE_ATTRIBUTES("fare_attributes.txt"),
// FARE_RULES("fare_rules.txt"),
// FREQUENCIES("frequencies.txt"),
STOPS("stops.txt"),
ROUTES("routes.txt"),
// SHAPES("shapes.txt"),
TRIPS("trips.txt"),
STOP_TIMES("stop_times.txt");
enum GtfsScheduleFile {
// FEED_INFO("feed_info.txt", Presence.OPTIONAL),
// ATTRIBUTIONS("attributions.txt", Presence.OPTIONAL),
AGENCY("agency.txt", Presence.REQUIRED),
CALENDAR("calendar.txt", Presence.CONDITIONALLY_REQUIRED),
CALENDAR_DATES("calendar_dates.txt", Presence.CONDITIONALLY_REQUIRED),
// FARE_ATTRIBUTES("fare_attributes.txt", Presence.OPTIONAL),
// FARE_RULES("fare_rules.txt", Presence.OPTIONAL),
// FREQUENCIES("frequencies.txt", Presence.OPTIONAL),
STOPS("stops.txt", Presence.REQUIRED),
ROUTES("routes.txt", Presence.REQUIRED),
// SHAPES("shapes.txt", Presence.OPTIONAL),
TRIPS("trips.txt", Presence.REQUIRED),
STOP_TIMES("stop_times.txt", Presence.REQUIRED);
// TRANSFERS("transfers.txt", Presence.OPTIONAL);

private final String fileName;
private final Presence presence;

public enum Presence {
REQUIRED,
OPTIONAL,
CONDITIONALLY_REQUIRED,
CONDITIONALLY_FORBIDDEN,
RECOMMENDED
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,8 @@ private void parseStop(CSVRecord record) {
}

private void parseRoute(CSVRecord record) {
// TODO: Route types are not standardized in any way.
// RouteType.parse(record.get("route_type"))
builder.addRoute(record.get("route_id"), record.get("agency_id"), record.get("route_short_name"),
record.get("route_long_name"), RouteType.RAIL);
record.get("route_long_name"), RouteType.parse(record.get("route_type")));
}

private void parseTrips(CSVRecord record) {
Expand Down
14 changes: 6 additions & 8 deletions src/main/java/ch/naviqore/gtfs/schedule/GtfsScheduleReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,7 @@
import org.apache.commons.io.ByteOrderMark;
import org.apache.commons.io.input.BOMInputStream;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
Expand Down Expand Up @@ -44,8 +41,8 @@ private static void readFromDirectory(File directory, GtfsScheduleParser parser)
if (csvFile.exists()) {
log.info("Reading GTFS CSV file: {}", csvFile.getAbsolutePath());
readCsvFile(csvFile, parser, fileType);
} else {
log.warn("GTFS CSV file {} not found", csvFile.getAbsolutePath());
} else if (fileType.getPresence() == GtfsScheduleFile.Presence.REQUIRED) {
throw new FileNotFoundException("Required GTFS CSV file" + csvFile.getAbsolutePath() + " not found");
}
}
}
Expand All @@ -63,8 +60,9 @@ private static void readFromZip(File zipFile, GtfsScheduleParser parser) throws
.get(), StandardCharsets.UTF_8)) {
readCsvRecords(reader, parser, fileType);
}
} else {
log.warn("GTFS file {} not found in ZIP", fileType.getFileName());
} else if (fileType.getPresence() == GtfsScheduleFile.Presence.REQUIRED) {
throw new FileNotFoundException(
"Required GTFS CSV file" + fileType.getFileName() + " not found in ZIP");
}
}
}
Expand Down
38 changes: 38 additions & 0 deletions src/main/java/ch/naviqore/gtfs/schedule/type/DefaultRouteType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package ch.naviqore.gtfs.schedule.type;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
@Getter
public enum DefaultRouteType implements RouteType {
TRAM(0, "Tram, Streetcar, Light rail. Any light rail or street level system within a metropolitan area."),
SUBWAY(1, "Subway, Metro. Any underground rail system within a metropolitan area."),
RAIL(2, "Rail. Used for intercity or long-distance travel."),
BUS(3, "Bus. Used for short- and long-distance bus routes."),
FERRY(4, "Ferry. Used for short- and long-distance boat service."),
CABLE_TRAM(5,
"Cable tram. Used for street-level rail cars where the cable runs beneath the vehicle (e.g., cable car in San Francisco)."),
AERIAL_LIFT(6,
"Aerial lift, suspended cable car (e.g., gondola lift, aerial tramway). Cable transport where cabins, cars, gondolas or open chairs are suspended by means of one or more cables."),
FUNICULAR(7, "Funicular. Any rail system designed for steep inclines."),
TROLLEYBUS(11, "Trolleybus. Electric buses that draw power from overhead wires using poles."),
MONORAIL(12, "Monorail. Railway in which the track consists of a single rail or a beam.");

private final int code;
private final String description;

public static DefaultRouteType parse(String code) {
return parse(Integer.parseInt(code));
}

public static DefaultRouteType parse(int code) {
for (DefaultRouteType type : DefaultRouteType.values()) {
if (type.code == code) {
return type;
}
}
throw new IllegalArgumentException("No default route type with code " + code + " found");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package ch.naviqore.gtfs.schedule.type;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
@Getter
public enum HierarchicalVehicleType implements RouteType {
RAILWAY_SERVICE(100, "Railway Service"),
HIGH_SPEED_RAIL_SERVICE(101, "High Speed Rail Service"),
LONG_DISTANCE_TRAINS(102, "Long Distance Trains"),
INTER_REGIONAL_RAIL_SERVICE(103, "Inter Regional Rail Service"),
CAR_TRANSPORT_RAIL_SERVICE(104, "Car Transport Rail Service"),
SLEEPER_RAIL_SERVICE(105, "Sleeper Rail Service"),
REGIONAL_RAIL_SERVICE(106, "Regional Rail Service"),
TOURIST_RAILWAY_SERVICE(107, "Tourist Railway Service"),
RAIL_SHUTTLE_WITHIN_COMPLEX(108, "Rail Shuttle (Within Complex)"),
SUBURBAN_RAILWAY(109, "Suburban Railway"),
REPLACEMENT_RAIL_SERVICE(110, "Replacement Rail Service"),
SPECIAL_RAIL_SERVICE(111, "Special Rail Service"),
LORRY_TRANSPORT_RAIL_SERVICE(112, "Lorry Transport Rail Service"),
ALL_RAIL_SERVICES(113, "All Rail Services"),
CROSS_COUNTRY_RAIL_SERVICE(114, "Cross-Country Rail Service"),
VEHICLE_TRANSPORT_RAIL_SERVICE(115, "Vehicle Transport Rail Service"),
RACK_AND_PINION_RAILWAY(116, "Rack and Pinion Railway"),
ADDITIONAL_RAIL_SERVICE(117, "Additional Rail Service"),

COACH_SERVICE(200, "Coach Service"),
INTERNATIONAL_COACH_SERVICE(201, "International Coach Service"),
NATIONAL_COACH_SERVICE(202, "National Coach Service"),
SHUTTLE_COACH_SERVICE(203, "Shuttle Coach Service"),
REGIONAL_COACH_SERVICE(204, "Regional Coach Service"),
SPECIAL_COACH_SERVICE(205, "Special Coach Service"),
SIGHTSEEING_COACH_SERVICE(206, "Sightseeing Coach Service"),
TOURIST_COACH_SERVICE(207, "Tourist Coach Service"),
COMMUTER_COACH_SERVICE(208, "Commuter Coach Service"),
ALL_COACH_SERVICES(209, "All Coach Services"),

URBAN_RAILWAY_SERVICE(400, "Urban Railway Service"),
METRO_SERVICE(401, "Metro Service"),
UNDERGROUND_SERVICE(402, "Underground Service"),
ALL_URBAN_RAILWAY_SERVICES(404, "All Urban Railway Services"),
MONORAIL(405, "Monorail"),

BUS_SERVICE(700, "Bus Service"),
REGIONAL_BUS_SERVICE(701, "Regional Bus Service"),
EXPRESS_BUS_SERVICE(702, "Express Bus Service"),
LOCAL_BUS_SERVICE(704, "Local Bus Service"),
NIGHT_BUS_SERVICE(705, "Night Bus Service"),
POST_BUS_SERVICE(706, "Post Bus Service"),
SPECIAL_NEEDS_BUS(707, "Special Needs Bus"),
MOBILITY_BUS_SERVICE(708, "Mobility Bus Service"),
MOBILITY_BUS_FOR_REGISTERED_DISABLED(709, "Mobility Bus for Registered Disabled"),
SIGHTSEEING_BUS(710, "Sightseeing Bus"),
SHUTTLE_BUS(711, "Shuttle Bus"),
SCHOOL_BUS(712, "School Bus"),
SCHOOL_AND_PUBLIC_SERVICE_BUS(713, "School and Public Service Bus"),
RAIL_REPLACEMENT_BUS_SERVICE(714, "Rail Replacement Bus Service"),
DEMAND_AND_RESPONSE_BUS_SERVICE(715, "Demand and Response Bus Service"),
ALL_BUS_SERVICES(716, "All Bus Services"),

TROLLEYBUS_SERVICE(800, "Trolleybus Service"),

TRAM_SERVICE(900, "Tram Service"),
CITY_TRAM_SERVICE(901, "City Tram Service"),
LOCAL_TRAM_SERVICE(902, "Local Tram Service"),
REGIONAL_TRAM_SERVICE(903, "Regional Tram Service"),
SIGHTSEEING_TRAM_SERVICE(904, "Sightseeing Tram Service"),
SHUTTLE_TRAM_SERVICE(905, "Shuttle Tram Service"),
ALL_TRAM_SERVICES(906, "All Tram Services"),

WATER_TRANSPORT_SERVICE(1000, "Water Transport Service"),
AIR_SERVICE(1100, "Air Service"),

FERRY_SERVICE(1200, "Ferry Service"),

AERIAL_LIFT_SERVICE(1300, "Aerial Lift Service"),
TELECABIN_SERVICE(1301, "Telecabin Service"),
CABLE_CAR_SERVICE(1302, "Cable Car Service"),
ELEVATOR_SERVICE(1303, "Elevator Service"),
CHAIR_LIFT_SERVICE(1304, "Chair Lift Service"),
DRAG_LIFT_SERVICE(1305, "Drag Lift Service"),
SMALL_TELECABIN_SERVICE(1306, "Small Telecabin Service"),
ALL_TELECABIN_SERVICES(1307, "All Telecabin Services"),

FUNICULAR_SERVICE(1400, "Funicular Service"),

TAXI_SERVICE(1500, "Taxi Service"),
COMMUNAL_TAXI_SERVICE(1501, "Communal Taxi Service"),
WATER_TAXI_SERVICE(1502, "Water Taxi Service"),
RAIL_TAXI_SERVICE(1503, "Rail Taxi Service"),
BIKE_TAXI_SERVICE(1504, "Bike Taxi Service"),
LICENSED_TAXI_SERVICE(1505, "Licensed Taxi Service"),
PRIVATE_HIRE_SERVICE_VEHICLE(1506, "Private Hire Service Vehicle"),
ALL_TAXI_SERVICES(1507, "All Taxi Services"),

MISCELLANEOUS_SERVICE(1700, "Miscellaneous Service"),
HORSE_DRAWN_CARRIAGE(1702, "Horse-drawn Carriage");

private final int code;
private final String description;

public static HierarchicalVehicleType parse(String code) {
return parse(Integer.parseInt(code));
}

public static HierarchicalVehicleType parse(int code) {
for (HierarchicalVehicleType type : HierarchicalVehicleType.values()) {
if (type.code == code) {
return type;
}
}
throw new IllegalArgumentException("No hierarchical vehicle type with code " + code + " found");
}
}
66 changes: 37 additions & 29 deletions src/main/java/ch/naviqore/gtfs/schedule/type/RouteType.java
Original file line number Diff line number Diff line change
@@ -1,38 +1,46 @@
package ch.naviqore.gtfs.schedule.type;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
/**
* Provides a unified approach to handling different modes of transportation of routes within a GTFS feed. Implementing
* this interface allows for retrieval of both unique identifier codes and descriptions of transportation route types.
*
* @author munterfi
*/
public interface RouteType {

@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
@Getter
public enum RouteType {
TRAM(0, "Tram, Streetcar, Light rail. Any light rail or street level system within a metropolitan area."),
SUBWAY(1, "Subway, Metro. Any underground rail system within a metropolitan area."),
RAIL(2, "Rail. Used for intercity or long-distance travel."),
BUS(3, "Bus. Used for short- and long-distance bus routes."),
FERRY(4, "Ferry. Used for short- and long-distance boat service."),
CABLE_TRAM(5,
"Cable tram. Used for street-level rail cars where the cable runs beneath the vehicle (e.g., cable car in San Francisco)."),
AERIAL_LIFT(6,
"Aerial lift, suspended cable car (e.g., gondola lift, aerial tramway). Cable transport where cabins, cars, gondolas or open chairs are suspended by means of one or more cables."),
FUNICULAR(7, "Funicular. Any rail system designed for steep inclines."),
TROLLEYBUS(11, "Trolleybus. Electric buses that draw power from overhead wires using poles."),
MONORAIL(12, "Monorail. Railway in which the track consists of a single rail or a beam.");
/**
* Parses a string to the corresponding RouteType: Either default GTFS route type or Hierarchical Vehicle Type
* (HVT).
*
* @param code the string code to parse
* @return the corresponding RouteType
* @throws NumberFormatException if the code is not a valid integer
* @throws IllegalArgumentException if the code is negative or invalid
*/

private final int value;
private final String description;

public static RouteType parse(String value) {
return parse(Integer.parseInt(value));
static RouteType parse(String code) {
return parse(Integer.parseInt(code));
}

public static RouteType parse(int value) {
for (RouteType type : RouteType.values()) {
if (type.value == value) {
return type;
}
static RouteType parse(int code) {
if (code < 0) {
throw new IllegalArgumentException("Invalid negative RouteType code: " + code);
}
if (code <= 12) {
return DefaultRouteType.parse(code);
} else {
return HierarchicalVehicleType.parse(code);
}
throw new IllegalArgumentException("No route type with value " + value + " found");
}

/**
* Retrieves the code associated with the route type.
*/
int getCode();

/**
* Retrieves a description of the route type.
*/
String getDescription();

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
public final class ServiceDayTime implements Comparable<ServiceDayTime> {
private final int totalSeconds;

public ServiceDayTime(int seconds) {
this.totalSeconds = seconds;
}

public ServiceDayTime(int hours, int minutes, int seconds) {
this.totalSeconds = seconds + 60 * minutes + 3600 * hours;
}
Expand Down
Loading
Loading