diff --git a/src/main/java/fi/hsl/transitdata/omm/OmmAlertHandler.java b/src/main/java/fi/hsl/transitdata/omm/OmmAlertHandler.java index 7740bcf..466b32a 100644 --- a/src/main/java/fi/hsl/transitdata/omm/OmmAlertHandler.java +++ b/src/main/java/fi/hsl/transitdata/omm/OmmAlertHandler.java @@ -4,11 +4,13 @@ import fi.hsl.common.transitdata.TransitdataProperties; import fi.hsl.common.transitdata.proto.InternalMessages; import fi.hsl.transitdata.omm.db.BulletinDAO; +import fi.hsl.transitdata.omm.db.DisruptionDAO; import fi.hsl.transitdata.omm.db.LineDAO; import fi.hsl.transitdata.omm.db.OmmDbConnector; import fi.hsl.transitdata.omm.db.StopPointDAO; import fi.hsl.transitdata.omm.models.AlertState; import fi.hsl.transitdata.omm.models.Bulletin; +import fi.hsl.transitdata.omm.models.DisruptionRoute; import fi.hsl.transitdata.omm.models.Line; import fi.hsl.transitdata.omm.models.Route; import fi.hsl.transitdata.omm.models.StopPoint; @@ -61,13 +63,16 @@ public void pollAndSend() throws SQLException, PulsarClientException, Exception //For some reason the connection seem to be flaky, let's reconnect on each request. ommConnector.connect(); + DisruptionDAO disruptionDAO = ommConnector.getDisruptionDAO(); + List disruptionRoutes = disruptionDAO.getActiveDisruptions(); + BulletinDAO bulletinDAO = ommConnector.getBulletinDAO(); LineDAO lineDAO = ommConnector.getLineDAO(); StopPointDAO stopPointDAO = ommConnector.getStopPointDAO(); List bulletins = bulletinDAO.getActiveBulletins(); AlertState latestState = new AlertState(bulletins); - + if (!LocalDate.now().equals(linesUpdateDate)) { lines = lineDAO.getAllLines(); linesUpdateDate = LocalDate.now(); @@ -81,7 +86,7 @@ public void pollAndSend() throws SQLException, PulsarClientException, Exception // We want to keep Pulsar internal timestamps as accurate as possible (ms) but GTFS-RT expects milliseconds final long currentTimestampUtcMs = ZonedDateTime.now(ZoneId.of(timeZone)).toInstant().toEpochMilli(); - final InternalMessages.ServiceAlert alert = createServiceAlert(bulletins, lines, stopPoints, timeZone); + final InternalMessages.ServiceAlert alert = createServiceAlert(bulletins, lines, stopPoints, disruptionRoutes, timeZone); sendPulsarMessage(alert, currentTimestampUtcMs); } else { log.info("No changes to current Service Alerts."); @@ -93,11 +98,11 @@ public void pollAndSend() throws SQLException, PulsarClientException, Exception } } - static InternalMessages.ServiceAlert createServiceAlert(final List bulletins, final Map lines, final Map> stopPoints, final String timeZone) { + static InternalMessages.ServiceAlert createServiceAlert(final List bulletins, final Map lines, final Map> stopPoints, List disruptionRoutes, final String timeZone) { final InternalMessages.ServiceAlert.Builder builder = InternalMessages.ServiceAlert.newBuilder(); builder.setSchemaVersion(builder.getSchemaVersion()); final List internalMessageBulletins = bulletins.stream() - .map(bulletin -> createBulletin(bulletin, lines, stopPoints, timeZone)) + .map(bulletin -> createBulletin(bulletin, lines, stopPoints, disruptionRoutes, timeZone)) .filter(Optional::isPresent) .map(Optional::get) .collect(Collectors.toList()); @@ -110,7 +115,7 @@ private static long toUtcEpochMs(final LocalDateTime localTimestamp, final Strin return localTimestamp.atZone(zone).toInstant().toEpochMilli(); } - static Optional createBulletin(final Bulletin bulletin, final Map lines, final Map> stopPoints, final String timezone) { + static Optional createBulletin(final Bulletin bulletin, final Map lines, final Map> stopPoints, List disruptionRoutes, final String timezone) { Optional maybeBulletin; try { final InternalMessages.Bulletin.Builder builder = InternalMessages.Bulletin.newBuilder(); @@ -144,7 +149,7 @@ static Optional createBulletin(final Bulletin bulleti builder.addAllTitles(bulletin.titles); builder.addAllDescriptions(bulletin.descriptions); builder.addAllUrls(bulletin.urls); - + builder.addAllAffectedDisruptionRoutes(disruptionRoutes); List affectedRoutes = getAffectedRoutes(bulletin, lines); List affectedStops = getAffectedStops(bulletin, stopPoints); if (affectedRoutes.isEmpty() && affectedStops.isEmpty() && !bulletin.affectsAllRoutes && !bulletin.affectsAllStops) { diff --git a/src/main/java/fi/hsl/transitdata/omm/db/DisruptionDAO.java b/src/main/java/fi/hsl/transitdata/omm/db/DisruptionDAO.java new file mode 100644 index 0000000..151e74a --- /dev/null +++ b/src/main/java/fi/hsl/transitdata/omm/db/DisruptionDAO.java @@ -0,0 +1,10 @@ +package fi.hsl.transitdata.omm.db; + +import fi.hsl.transitdata.omm.models.DisruptionRoute; + +import java.sql.SQLException; +import java.util.List; + +public interface DisruptionDAO { + List getActiveDisruptions() throws SQLException; +} diff --git a/src/main/java/fi/hsl/transitdata/omm/db/DisruptionDAOImpl.java b/src/main/java/fi/hsl/transitdata/omm/db/DisruptionDAOImpl.java new file mode 100644 index 0000000..90f96bd --- /dev/null +++ b/src/main/java/fi/hsl/transitdata/omm/db/DisruptionDAOImpl.java @@ -0,0 +1,141 @@ +package fi.hsl.transitdata.omm.db; + + +import fi.hsl.common.files.FileUtils; +import fi.hsl.common.transitdata.proto.InternalMessages; +import fi.hsl.transitdata.omm.models.DisruptionRoute; +import fi.hsl.transitdata.omm.models.DisruptionRouteLink; +import fi.hsl.transitdata.omm.models.cancellations.Stop; + +import java.sql.Connection; +import java.io.InputStream; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.*; +import java.util.stream.Collectors; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; + +public class DisruptionDAOImpl extends DAOImplBase implements DisruptionDAO { + + String queryString; + String queryLinksString; + String timezone; + int pollIntervalInSeconds; + boolean queryAllModifiedAlerts; + + public DisruptionDAOImpl(Connection connection, String timezone) { + super(connection); + this.timezone = timezone; + this.pollIntervalInSeconds = pollIntervalInSeconds; + this.queryAllModifiedAlerts = queryAllModifiedAlerts; + queryString = createQuery("/disruption_routes.sql"); + queryLinksString = createQuery("/disruption_route_links.sql"); + } + + private List parseDisruptionRoutes(ResultSet resultSet, Map stopsByGid) throws SQLException { + HashMap> disruptionLinks = getActiveDisruptionLinks(); + List disruptionRoutes = new ArrayList<>(); + log.info("Processing disruptionRoutes resultset"); + while (resultSet.next()) { + try { + String disruptionRouteId = resultSet.getString("DISRUPTION_ROUTES_ID"); + ArrayList disruptionRouteLinks = new ArrayList(); + ArrayList disruptionRouteLinksByRouteId = disruptionLinks.get(disruptionRouteId); + if (disruptionRouteLinksByRouteId != null) { + disruptionRouteLinks = disruptionRouteLinksByRouteId; + } + String startStopGid = resultSet.getString("START_STOP_ID"); + String startStopId = stopsByGid.containsKey(startStopGid) ? stopsByGid.get(startStopGid).stopId : ""; + String endStopGid = resultSet.getString("END_STOP_ID"); + String endStopId = stopsByGid.containsKey(startStopGid) ? stopsByGid.get(endStopGid).stopId : ""; + + String affectedRoutes = resultSet.getString("AFFECTED_ROUTE_IDS"); + List affectedRoutesList = Arrays.stream(affectedRoutes.split(",")).map(String::trim).collect(Collectors.toList()); + + String validFrom = resultSet.getString("DC_VALID_FROM"); + String validTo = resultSet.getString("DC_VALID_TO"); + + disruptionRoutes.add(new DisruptionRoute(disruptionRouteId, startStopId, endStopId, affectedRoutesList, validFrom, validTo, timezone, disruptionRouteLinks)); + + String name = resultSet.getString("NAME"); + String description = resultSet.getString("DESCRIPTION"); + String type = resultSet.getString("DC_TYPE"); + log.info("Found disruption route with name: {}, description: {} and type: {}", name, description, type); + } catch (IllegalArgumentException iae) { + log.error("Error while parsing the disruptionRoutes resultset", iae); + } + } + log.info("Found total {} disruption routes", disruptionRoutes.size()); + return disruptionRoutes; + } + + private String createQuery(String query) { + InputStream stream = getClass().getResourceAsStream(query); + try { + return FileUtils.readFileFromStreamOrThrow(stream); + } catch (Exception e) { + log.error("Error in reading sql from file:", e); + return null; + } + } + + public static String localDateAsString(Instant instant, String zoneId) { + return DateTimeFormatter.ofPattern("yyyy-MM-dd").format(instant.atZone(ZoneId.of(zoneId))); + } + + public HashMap> getActiveDisruptionLinks() throws SQLException { + log.info("Querying disruption routes from database"); + List links = new ArrayList<>(); + HashMap> linksByRouteId = new HashMap>(); + String preparedString = queryLinksString; + try (PreparedStatement statement = connection.prepareStatement(preparedString)) { + ResultSet resultSet = statement.executeQuery(); + while (resultSet.next()) { + String id = resultSet.getString("disruption_routes_id"); + String deviationId = resultSet.getString("deviation_case_id"); + String startStopId = resultSet.getString("start_stop_id"); + String endStopId = resultSet.getString("end_stop_id"); + String sequenceNumber = resultSet.getString("link_location_sequence_number"); + String latitude = resultSet.getString("latitude"); + String longitude = resultSet.getString("longitude"); + DisruptionRouteLink disruptionLink = new DisruptionRouteLink(id, deviationId, startStopId, endStopId, sequenceNumber, latitude, longitude); + + ArrayList list = linksByRouteId.get(id); + if (list != null) { + list.add(disruptionLink); + linksByRouteId.replace(id, list); + } else { + ArrayList newList = new ArrayList(); + newList.add(disruptionLink); + linksByRouteId.put(id, newList); + } + } + } + catch (Exception e) { + log.error("Error while querying and processing messages", e); + throw e; + } + return linksByRouteId; + } + + @Override + public List getActiveDisruptions() throws SQLException { + log.info("Querying disruption route links from database"); + String dateFrom = localDateAsString(Instant.now(), timezone); + String preparedString = queryString.replace("VAR_DATE_FROM", "1970-03-07"); + try (PreparedStatement statement = connection.prepareStatement(preparedString)) { + ResultSet resultSet = statement.executeQuery(); + HashMap stopsByGid = new HashMap(); + return parseDisruptionRoutes(resultSet, stopsByGid); + } + catch (Exception e) { + log.error("Error while querying and processing messages", e); + throw e; + } + } +} diff --git a/src/main/java/fi/hsl/transitdata/omm/db/OmmDbConnector.java b/src/main/java/fi/hsl/transitdata/omm/db/OmmDbConnector.java index ee7c551..9bed199 100644 --- a/src/main/java/fi/hsl/transitdata/omm/db/OmmDbConnector.java +++ b/src/main/java/fi/hsl/transitdata/omm/db/OmmDbConnector.java @@ -16,6 +16,7 @@ public class OmmDbConnector implements AutoCloseable { private boolean queryAllModifiedAlerts; private BulletinDAO bulletinDAO; + private DisruptionDAO disruptionDAO; private LineDAO lineDAO; private StopPointDAO stopPointDAO; @@ -35,6 +36,7 @@ public OmmDbConnector(Config config, int pollIntervalInSeconds, String jdbcConne public void connect() throws SQLException { connection = DriverManager.getConnection(connectionString); bulletinDAO = new BulletinDAOImpl(connection, timezone, pollIntervalInSeconds, queryAllModifiedAlerts); + disruptionDAO = new DisruptionDAOImpl(connection, timezone); stopPointDAO = new StopPointDAOImpl(connection, timezone); lineDAO = new LineDAOImpl(connection); } @@ -42,6 +44,7 @@ public void connect() throws SQLException { @Override public void close() throws Exception { bulletinDAO = null; + disruptionDAO = null; stopPointDAO = null; lineDAO = null; connection.close(); @@ -52,6 +55,11 @@ public BulletinDAO getBulletinDAO() { return bulletinDAO; } + + public DisruptionDAO getDisruptionDAO() { + return disruptionDAO; + } + public LineDAO getLineDAO() { return lineDAO; } diff --git a/src/main/java/fi/hsl/transitdata/omm/models/DisruptionRoute.java b/src/main/java/fi/hsl/transitdata/omm/models/DisruptionRoute.java new file mode 100644 index 0000000..c9f5d4e --- /dev/null +++ b/src/main/java/fi/hsl/transitdata/omm/models/DisruptionRoute.java @@ -0,0 +1,127 @@ +package fi.hsl.transitdata.omm.models; + +import fi.hsl.common.transitdata.proto.InternalMessages; +import fi.hsl.transitdata.omm.models.cancellations.Journey; +import fi.hsl.transitdata.omm.models.cancellations.JourneyPattern; +import fi.hsl.transitdata.omm.models.cancellations.JourneyPatternStop; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.stream.Collectors; + +public class DisruptionRoute { + private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + private static final Logger log = LoggerFactory.getLogger(DisruptionRoute.class); + + public final String disruptionRouteId; + public final String startStopId; + public final String endStopId; + private final Optional validFromDate; + private final Optional validToDate; + private final ZoneId timezoneId; + public final Collection affectedRoutes; + private final Map> affectedJourneysByJourneyPatternId; + private final Map> affectedStopIdsByJourneyPatternId; + public final ArrayList disruptionRouteLinks; + + public DisruptionRoute(String disruptionRouteId, String startStopId, String endStopId, Collection affectedRoutes, String validFromDate, String validToDate, String timezone, ArrayList disruptionRouteLinks) { + this.disruptionRouteId = disruptionRouteId; + this.startStopId = startStopId; + this.endStopId = endStopId; + this.validFromDate = getDateOrEmpty(validFromDate); + this.validToDate = getDateOrEmpty(validToDate); + this.timezoneId = ZoneId.of(timezone); + this.affectedRoutes = affectedRoutes; + this.affectedJourneysByJourneyPatternId = new HashMap<>(); + this.affectedStopIdsByJourneyPatternId = new HashMap<>(); + this.disruptionRouteLinks = disruptionRouteLinks; + } + + public void addAffectedJourneys(List journeys) { + for (Journey journey : journeys) { + if (!affectedJourneysByJourneyPatternId.containsKey(journey.journeyPatternId)) { + affectedJourneysByJourneyPatternId.put(journey.journeyPatternId, new ArrayList<>()); + } + affectedJourneysByJourneyPatternId.get(journey.journeyPatternId).add(journey); + } + } + + public Optional getValidFrom() { + return validFromDate.map(DATE_TIME_FORMATTER::format); + } + + public Optional getValidTo() { + return validToDate.map(DATE_TIME_FORMATTER::format); + } + + public Collection getAffectedJourneyPatternIds() { + return affectedJourneysByJourneyPatternId.keySet(); + } + + public void findAddAffectedStops(Map journeyPatternsById) { + for (String jpId : affectedJourneysByJourneyPatternId.keySet()) { + JourneyPattern journeyPattern = journeyPatternsById.get(jpId); + Optional> stopsBetween = journeyPattern.getStopsBetweenTwoStops(startStopId, endStopId); + stopsBetween.ifPresent(stops -> affectedStopIdsByJourneyPatternId.put(jpId, stops.stream().map(stop -> stop.stopId).collect(Collectors.toList()))); + } + } + + public Optional getDateOrEmpty(String dateStr) { + try { + return Optional.of(LocalDateTime.parse(dateStr.replace(" ", "T"))); + } catch (Exception e) { + return Optional.empty(); + } + } + + public List getAsStopCancellations() { + // find unique cancelledStopIds from all affected stop ids + Set cancelledStopIds = affectedStopIdsByJourneyPatternId.values().stream() + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + + if (cancelledStopIds.isEmpty()) { + log.info("No stop cancellations were created by disruption route {}", disruptionRouteId); + return Collections.emptyList(); + } + + validateStopCancellations(cancelledStopIds); + return cancelledStopIds.stream().map(stopId -> { + InternalMessages.StopCancellations.StopCancellation.Builder builder = InternalMessages.StopCancellations.StopCancellation.newBuilder(); + builder.setCause(InternalMessages.StopCancellations.Cause.JOURNEY_PATTERN_DETOUR); + builder.setStopId(stopId); + validFromDate.ifPresent(dateTime -> builder.setValidFromUnixS(toUtcEpochSeconds(dateTime))); + validToDate.ifPresent(dateTime -> builder.setValidToUnixS(toUtcEpochSeconds(dateTime))); + builder.addAllAffectedJourneyPatternIds(new ArrayList<>(affectedStopIdsByJourneyPatternId.keySet())); + return builder.build(); + }).collect(Collectors.toList()); + } + + //TODO: what does this do? + private void validateStopCancellations(Set cancelledStopIds) { + // check that there's no journey pattern specific stop cancellations + Set compareStopIds = new HashSet<>(affectedStopIdsByJourneyPatternId.values().iterator().next()); + if (!cancelledStopIds.equals(compareStopIds)) { + log.warn("Found journey pattern specific stop cancellations by disruption route"); + } + } + + public List getAffectedJourneyPatterns(Map journeyPatternById) { + return affectedJourneysByJourneyPatternId.keySet().stream().map(jpId -> { + JourneyPattern affectedJourneyPattern = journeyPatternById.get(jpId).createNewWithSameStops(); + affectedJourneyPattern.addAffectedJourneys(affectedJourneysByJourneyPatternId.get(jpId)); + return affectedJourneyPattern.getAsProtoBuf(); + }).collect(Collectors.toList()); + } + + private Long toUtcEpochSeconds(LocalDateTime dt) { + // convert dt to Unix time (i.e. Epoch time in seconds) + return dt.atZone(timezoneId).toEpochSecond(); + } + +} diff --git a/src/main/java/fi/hsl/transitdata/omm/models/DisruptionRouteLink.java b/src/main/java/fi/hsl/transitdata/omm/models/DisruptionRouteLink.java new file mode 100644 index 0000000..789a362 --- /dev/null +++ b/src/main/java/fi/hsl/transitdata/omm/models/DisruptionRouteLink.java @@ -0,0 +1,22 @@ +package fi.hsl.transitdata.omm.models; + +public class DisruptionRouteLink { + public final String id; + public final String deviationId; + public final String startStopId; + public final String endStopId; + public final String sequenceNumber; + public final String latitude; + public final String longitude; + + public DisruptionRouteLink(String id, String deviationId, String startStopId, String endStopId, String sequenceNumber, String latitude, String longitude) { + this.id = id; + this.deviationId = deviationId; + this.startStopId = startStopId; + this.endStopId = endStopId; + this.sequenceNumber = sequenceNumber; + this.latitude = latitude; + this.longitude = longitude; + } + +} diff --git a/src/main/java/fi/hsl/transitdata/omm/models/cancellations/Journey.java b/src/main/java/fi/hsl/transitdata/omm/models/cancellations/Journey.java new file mode 100644 index 0000000..f957fdb --- /dev/null +++ b/src/main/java/fi/hsl/transitdata/omm/models/cancellations/Journey.java @@ -0,0 +1,34 @@ +package fi.hsl.transitdata.omm.models.cancellations; + +import fi.hsl.common.transitdata.proto.InternalMessages; + +public class Journey { + + private final String tripId; + private final String operatingDay; + private final String routeName; + private final int direction; + private final String startTime; + public final String journeyPatternId; + + public Journey(String tripid, String operatingDay, String routeName, int direction, String startTime, String journeyPatternId) { + this.tripId = tripid; + this.operatingDay = operatingDay; + this.routeName = routeName; + this.direction = direction; + this.startTime = startTime; + this.journeyPatternId = journeyPatternId; + } + + public InternalMessages.TripInfo getAsProtoBuf() { + InternalMessages.TripInfo.Builder builder = InternalMessages.TripInfo.newBuilder(); + builder.setTripId(tripId); + builder.setOperatingDay(operatingDay); + builder.setRouteId(routeName); + builder.setDirectionId(direction); + builder.setStartTime(startTime); + builder.setScheduleType(InternalMessages.TripInfo.ScheduleType.SCHEDULED); + return builder.build(); + } + +} diff --git a/src/main/java/fi/hsl/transitdata/omm/models/cancellations/JourneyPattern.java b/src/main/java/fi/hsl/transitdata/omm/models/cancellations/JourneyPattern.java new file mode 100644 index 0000000..72ac449 --- /dev/null +++ b/src/main/java/fi/hsl/transitdata/omm/models/cancellations/JourneyPattern.java @@ -0,0 +1,67 @@ +package fi.hsl.transitdata.omm.models.cancellations; + +import fi.hsl.common.transitdata.proto.InternalMessages; + +import java.util.*; +import java.util.stream.Collectors; + +public class JourneyPattern { + + public final String id; + private final int stopCount; + private final Map stops = new HashMap<>(); + //Stop IDs sorted by stop sequence + private final NavigableSet stopIds = new TreeSet<>(Comparator.comparingInt(stopId -> stops.get(stopId).getSequence())); + private final List journeys = new ArrayList<>(); + + public JourneyPattern(String id, int stopCount) { + this.id = id; + this.stopCount = stopCount; + } + + public Collection getStopIds(){ + return stops.keySet(); + } + + public void addStop(JourneyPatternStop stop) { + if (!stops.containsKey(stop.stopId)) { + stops.put(stop.stopId, stop); + stopIds.add(stop.stopId); + } + } + + public JourneyPattern createNewWithSameStops() { + JourneyPattern copy = new JourneyPattern(id, stopCount); + copy.stops.putAll(stops); + copy.stopIds.addAll(stopIds); + return copy; + } + + public void addAffectedJourneys(List affectedJourneys) { + this.journeys.addAll(affectedJourneys); + } + + public Optional> getStopsBetweenTwoStops(String startStopId, String endStopId) { + //If the journey pattern does not contain either the start or end stop, return nothing + if (!stops.containsKey(startStopId) || !stops.containsKey(endStopId)) { + return Optional.empty(); + } + + Set stopIdsBetweenStops = stopIds.subSet(startStopId, false, endStopId, false); + if (stopIdsBetweenStops.isEmpty()) { + return Optional.empty(); + } + + return Optional.of(stopIdsBetweenStops.stream().map(stops::get).collect(Collectors.toList())); + } + + public InternalMessages.JourneyPattern getAsProtoBuf() { + InternalMessages.JourneyPattern.Builder builder = InternalMessages.JourneyPattern.newBuilder(); + builder.setJourneyPatternId(id); + builder.addAllStops(stopIds.stream().map(stops::get).map(JourneyPatternStop::getAsProtoBuf).collect(Collectors.toList())); + if (!journeys.isEmpty()) { + builder.addAllTrips(journeys.stream().map(Journey::getAsProtoBuf).collect(Collectors.toList())); + } + return builder.build(); + } +} diff --git a/src/main/java/fi/hsl/transitdata/omm/models/cancellations/JourneyPatternStop.java b/src/main/java/fi/hsl/transitdata/omm/models/cancellations/JourneyPatternStop.java new file mode 100644 index 0000000..eb69cca --- /dev/null +++ b/src/main/java/fi/hsl/transitdata/omm/models/cancellations/JourneyPatternStop.java @@ -0,0 +1,30 @@ +package fi.hsl.transitdata.omm.models.cancellations; + +import fi.hsl.common.transitdata.proto.InternalMessages; + +public class JourneyPatternStop { + + private final String stopGid; + public final String stopId; + private final Integer sequence; + private final String name; + + public JourneyPatternStop(String stopGid, String stopId, String name, Integer sequence) { + this.stopGid = stopGid; + this.stopId = stopId; + this.name = name; + this.sequence = sequence; + } + + public InternalMessages.JourneyPattern.Stop getAsProtoBuf() { + InternalMessages.JourneyPattern.Stop.Builder builder = InternalMessages.JourneyPattern.Stop.newBuilder(); + builder.setStopId(stopId); + builder.setStopSequence(sequence); + return builder.build(); + } + + public Integer getSequence() { + return this.sequence; + } + +} diff --git a/src/main/java/fi/hsl/transitdata/omm/models/cancellations/Stop.java b/src/main/java/fi/hsl/transitdata/omm/models/cancellations/Stop.java new file mode 100644 index 0000000..e37cd55 --- /dev/null +++ b/src/main/java/fi/hsl/transitdata/omm/models/cancellations/Stop.java @@ -0,0 +1,15 @@ +package fi.hsl.transitdata.omm.models.cancellations; + +public class Stop { + + public final String stopGid; + public final String stopId; + public final String name; + + public Stop(String stopGid, String stopId, String name) { + this.stopGid = stopGid; + this.stopId = stopId; + this.name = name; + } + +} diff --git a/src/main/resources/disruption_route_links.sql b/src/main/resources/disruption_route_links.sql new file mode 100644 index 0000000..9d8884a --- /dev/null +++ b/src/main/resources/disruption_route_links.sql @@ -0,0 +1,37 @@ +SELECT + DR.[disruption_routes_id], + DR.[pubtrans_id], + DR.[name], + DR.[deviation_case_id], + DR.[type], + DR.[based_on_trip_variant_id], + DR.[start_stop_id], + DR.[end_stop_id], + DR.[status], + DR.[created], + DR.[created_by], + Dlink.[detour_links_id], + Dlink.[disruption_routes_id], + Dlink.[link_id], + Dlink.[start_journey_pattern_point_id], + Dlink.[end_journey_pattern_point_id], + Dlink.[sequence_number], + Dlink.[last_modified], + Dlink.[last_modified_by], + Dlink.[last_modified_by_organisation], + Dlink.[status], + DlinkLoc.[detour_link_locations_id], + DlinkLoc.[detour_links_id], + DlinkLoc.[sequence_number] AS link_location_sequence_number, + DlinkLoc.[projection], + DlinkLoc.[latitude], + DlinkLoc.[longitude], + DlinkLoc.[last_modified], + DlinkLoc.[last_modified_by], + DlinkLoc.[last_modified_by_organisation], + DlinkLoc.[status] + FROM OMM_Community.dbo.[disruption_routes] DR + LEFT JOIN OMM_Community.dbo.detour_links Dlink ON Dlink.disruption_routes_id = DR.disruption_routes_id + LEFT JOIN OMM_Community.dbo.detour_link_locations DLinkLoc ON DLinkLoc.detour_links_id = Dlink.detour_links_id + WHERE Dlink.status = 'active' + ORDER BY Dlink.sequence_number, DLinkLoc.sequence_number; \ No newline at end of file diff --git a/src/main/resources/disruption_routes.sql b/src/main/resources/disruption_routes.sql new file mode 100644 index 0000000..3e7007e --- /dev/null +++ b/src/main/resources/disruption_routes.sql @@ -0,0 +1,23 @@ +SELECT DR.disruption_routes_id AS DISRUPTION_ROUTES_ID, + DR.name AS NAME, + DR.[type] AS DR_TYPE, + DR.based_on_trip_variant_id, + DR.start_stop_id AS START_STOP_ID, + DR.end_stop_id AS END_STOP_ID, + DR.status AS STATUS, + DR.last_modified_by, + DC.[type] AS DC_TYPE, + DC.last_modified_by, + DC.last_modified, + DC.valid_from AS DC_VALID_FROM, + DC.valid_to AS DC_VALID_TO, + B.valid_from AS B_VALID_FROM, + B.valid_to AS B_VALID_TO, + B.affected_route_ids AS AFFECTED_ROUTE_IDS, + BLM.description AS DESCRIPTION + FROM OMM_Community.dbo.disruption_routes AS DR + LEFT JOIN OMM_Community.dbo.deviation_cases AS DC ON DC.deviation_case_id = DR.deviation_case_id + LEFT JOIN OMM_Community.dbo.bulletins AS B ON B.bulletins_id = DC.bulletin_id + LEFT JOIN OMM_Community.dbo.bulletin_localized_messages AS BLM ON DC.bulletin_id = BLM.bulletins_id + WHERE (DC.valid_to >= 'VAR_DATE_FROM' OR DC.valid_to IS NULL) + ORDER BY DR.last_modified DESC; \ No newline at end of file diff --git a/src/test/java/fi/hsl/transitdata/omm/OmmAlertHandlerTest.java b/src/test/java/fi/hsl/transitdata/omm/OmmAlertHandlerTest.java index bfb8be2..78d25f4 100644 --- a/src/test/java/fi/hsl/transitdata/omm/OmmAlertHandlerTest.java +++ b/src/test/java/fi/hsl/transitdata/omm/OmmAlertHandlerTest.java @@ -3,10 +3,12 @@ import fi.hsl.common.transitdata.proto.InternalMessages; import fi.hsl.transitdata.omm.db.MockOmmConnector; import fi.hsl.transitdata.omm.models.Bulletin; +import fi.hsl.transitdata.omm.models.DisruptionRoute; import fi.hsl.transitdata.omm.models.Line; import fi.hsl.transitdata.omm.models.StopPoint; import org.junit.Test; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Optional; @@ -25,8 +27,8 @@ private InternalMessages.ServiceAlert createServiceAlertFromDefaultMockData() th List bulletins = connector.getBulletinDAO().getActiveBulletins(); Map lines = connector.getLineDAO().getAllLines(); Map> stops = connector.getStopPointDAO().getAllStopPoints(); - - final InternalMessages.ServiceAlert alert = OmmAlertHandler.createServiceAlert(bulletins, lines, stops, TIMEZONE); + List disruptionRoutes = new ArrayList(); + final InternalMessages.ServiceAlert alert = OmmAlertHandler.createServiceAlert(bulletins, lines, stops, disruptionRoutes, TIMEZONE); assertEquals(bulletins.size(), alert.getBulletinsCount()); validateMockDataFirstEntity(alert.getBulletinsList().get(0)); return alert; @@ -95,8 +97,8 @@ public void testOneBulletinThoroughly() throws Exception { final Optional maybeSelectedBulletin = bulletins.stream().filter(b -> b.id == 6431).findFirst(); assertTrue(maybeSelectedBulletin.isPresent()); final Bulletin selectedBulletin = maybeSelectedBulletin.get(); - - final Optional maybeBulletin = OmmAlertHandler.createBulletin(selectedBulletin, lines, stops, TIMEZONE); + List disruptionRoutes = new ArrayList(); + final Optional maybeBulletin = OmmAlertHandler.createBulletin(selectedBulletin, lines, stops, disruptionRoutes, TIMEZONE); assertTrue(maybeBulletin.isPresent()); final InternalMessages.Bulletin bulletin = maybeBulletin.get();