diff --git a/transitclock/src/main/java/org/transitclock/custom/aws/WmataAvlTypeUnmarshaller.java b/transitclock/src/main/java/org/transitclock/custom/aws/WmataAvlTypeUnmarshaller.java index 3be90c130..6234e7a7a 100644 --- a/transitclock/src/main/java/org/transitclock/custom/aws/WmataAvlTypeUnmarshaller.java +++ b/transitclock/src/main/java/org/transitclock/custom/aws/WmataAvlTypeUnmarshaller.java @@ -12,6 +12,7 @@ import org.transitclock.db.structs.AvlReport.AssignmentType; import com.amazonaws.services.sqs.model.Message; +import org.transitclock.db.structs.OccupancyStatus; /** * Implementation of SqsMessageUnmarshaller for WMATA data. @@ -95,6 +96,13 @@ private AvlReportWrapper toAvlReport(JSONObject jsonObj) { speed = (float) msgObj.getDouble("averageSpeed") * 0.3048f; // convert to m/s } + OccupancyStatus occupancyStatus = null; + if (msgObj.has("crowdingStatus")) { + String occupancyString = null; + occupancyString = msgObj.getString("crowdingStatus"); + occupancyStatus = OccupancyStatus.lenientParse(occupancyString); + } + Long forwarderTimeReceived = null; if (msgObj.has("received")) { forwarderTimeReceived = msgObj.getLong("received"); @@ -126,6 +134,9 @@ private AvlReportWrapper toAvlReport(JSONObject jsonObj) { String source = "sqs"; if (vehicleId != null && lat != null && lon != null && time != null) { AvlReport ar = new AvlReport(vehicleId, time, lat, lon, speed, heading, source); + if (occupancyStatus != null) { + ar.setOccupancyStatus(occupancyStatus); + } if (msgObj.has("blockAlpha")) { String blockAlpha = msgObj.getString("blockAlpha"); if (blockAlpha != null) { diff --git a/transitclock/src/main/java/org/transitclock/db/structs/AvlReport.java b/transitclock/src/main/java/org/transitclock/db/structs/AvlReport.java index e89233c1d..6b6d64313 100644 --- a/transitclock/src/main/java/org/transitclock/db/structs/AvlReport.java +++ b/transitclock/src/main/java/org/transitclock/db/structs/AvlReport.java @@ -119,7 +119,7 @@ public class AvlReport implements Serializable { // Can be block, trip, or route ID @Column(length=HibernateUtils.DEFAULT_ID_SIZE) private String assignmentId; // optional - + // The type of the assignment received in the AVL feed public enum AssignmentType { UNSET, @@ -160,7 +160,13 @@ public enum AssignmentType { // This parameter is optional. Set to null if data not available. @Column(length=HibernateUtils.DEFAULT_ID_SIZE) private final Float passengerFullness; - + + // Optional. Mirrors GTFS-RT occupancy status so it can be passed through + // we choose ordinal sacrificing readability for size! + @Column + @Enumerated(EnumType.ORDINAL) + private OccupancyStatus occupancyStatus; + // Optional. For containing additional info for a particular feed. // Not declared final because setField1() is used to set values. @Column(length=HibernateUtils.DEFAULT_ID_SIZE) @@ -179,7 +185,7 @@ public enum AssignmentType { LoggerFactory.getLogger(AvlReport.class); // Needed because serializable so can transmit using JMS or RMI - private static final long serialVersionUID = 92384928349823L; + private static final long serialVersionUID = 92384928349824L; /********************** Member Functions **************************/ @@ -795,6 +801,24 @@ public String getSource() { public void setSource(String source) { this.source=sized(source); } + + /** + * GTFS-RT inspired levels of crowding information. + * @return enumeration + */ + public OccupancyStatus getOccupancyStatus() { + return occupancyStatus; + } + + /** + * GTFS-RT inspired levels of crowding information. + */ + public void setOccupancyStatus(OccupancyStatus occupancyStatus) { + this.occupancyStatus = occupancyStatus; + } + + + /** * Returns how many msec elapsed between the GPS fix was generated * to the time it was finally processed. Returns 0 if timeProcessed diff --git a/transitclock/src/main/java/org/transitclock/db/structs/OccupancyStatus.java b/transitclock/src/main/java/org/transitclock/db/structs/OccupancyStatus.java new file mode 100644 index 000000000..458763a66 --- /dev/null +++ b/transitclock/src/main/java/org/transitclock/db/structs/OccupancyStatus.java @@ -0,0 +1,160 @@ +package org.transitclock.db.structs; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.Serializable; + +/** + * this mirrors GTFS-RT's occupancyStatus (2016 version): + * https://developers.google.com/transit/gtfs-realtime/reference/OccupancyStatus-vp + * + * Constants proposed here: + * https://github.com/OneBusAway/onebusaway-application-modules/issues/121 + * + * Borrowed from https://github.com/OneBusAway/onebusaway-application-modules/onebusaway-realtime-api + */ +public enum OccupancyStatus implements Serializable { + + /** + * proposed addition + */ + UNKNOWN(-1), + /** + * The vehicle is considered empty by most measures, has few or no passengers + * onboard, and is accepting passengers. + */ + EMPTY(0), + /** + * The vehicle has a large percentage of seats available. What percentage of + * free seats out of the total seats available is large enough to fall into + * this category is determined by the producer. + */ + MANY_SEATS_AVAILABLE(1), + /** + * The vehicle has a small percentage of seats available. What percentage + * of free seats out of the total seats available is small enough to fall + * into this category is determined by the producer. + */ + FEW_SEATS_AVAILABLE(2), + /** + * The vehicle can accommodate only standing passengers. + */ + STANDING_ROOM_ONLY(3), + /** + * The vehicle can accommodate only standing passengers but has limited + * space for them. + */ + CRUSHED_STANDING_ROOM_ONLY(4), + /** + * The vehicle is considered full by most measures but may still be allowing + * passengers to board. + */ + FULL(5), + /** + * The vehicle is not accepting passengers. + */ + NOT_ACCEPTING_PASSENGERS(6); + + private static Logger _log = LoggerFactory.getLogger(OccupancyStatus.class); + private int _status; + + OccupancyStatus() { + _status = -1; + } + + OccupancyStatus(int status) { + _status = status; + } + + public static OccupancyStatus lenientParse(String occupancyString) { + OccupancyStatus status = null; + try { + status = OccupancyStatus.valueOf(occupancyString); + } catch (IllegalArgumentException iae) { + return mapFromExternalSystems(occupancyString); + } + return status; + } + + private static OccupancyStatus mapFromExternalSystems(String occupancyString) { + if ("MANY SEATS".equals(occupancyString)) + return OccupancyStatus.MANY_SEATS_AVAILABLE; + if ("FEW SEATS".equals(occupancyString)) + return OccupancyStatus.FEW_SEATS_AVAILABLE; + throw new IllegalArgumentException(occupancyString + "not expected"); + } + + public int valueOf() { + return _status; + } + + public static boolean contains(String status) { + for (OccupancyStatus OccupancyStatus : values()) { + if (OccupancyStatus.name().equalsIgnoreCase(status)) { + return true; + } + } + return false; + } + + public String toString() { + return toCamelCase(this.name()); + } + + public static OccupancyStatus toEnum(int status) { + if (status == UNKNOWN.valueOf() || status < 0) + return UNKNOWN; + if (status == EMPTY.valueOf()) + return EMPTY; + if (status == MANY_SEATS_AVAILABLE.valueOf()) + return MANY_SEATS_AVAILABLE; + if (status == FEW_SEATS_AVAILABLE.valueOf()) + return FEW_SEATS_AVAILABLE; + if (status == STANDING_ROOM_ONLY.valueOf()) + return STANDING_ROOM_ONLY; + if (status == CRUSHED_STANDING_ROOM_ONLY.valueOf()) + return CRUSHED_STANDING_ROOM_ONLY; + if (status == FULL.valueOf()) + return FULL; + if (status == NOT_ACCEPTING_PASSENGERS.valueOf()) { + _log.warn("Occupancy Status set to NotAcceptingPassengers"); + return NOT_ACCEPTING_PASSENGERS; + } + throw new IllegalArgumentException("unexpected value " + status); + } + + public static OccupancyStatus toEnum(double rid) { + int status; + if (rid < 0.0) { + status = -1; + } else if (rid == 0.0) { + status = 0; + } else if (rid <= 25.0) { + status = 1; + } else if (rid <= 50.0) { + status = 2; + } else if (rid <= 75.0) { + status = 3; + } else if (rid <= 90.0) { + status = 4; + } else if (rid <= 100.0) { + status = 5; + } else { + status = 6; + } + return OccupancyStatus.toEnum(status); + } + + private String toCamelCase(String upperCase) { + if (upperCase == null || upperCase.length() == 0) return upperCase; + String[] parts = upperCase.split("_"); + StringBuffer camelCase = new StringBuffer(); + for (String part : parts) { + camelCase.append(part.substring(0, 1).toUpperCase()); + camelCase.append(part.substring(1).toLowerCase()); + } + String result = camelCase.substring(0, 1).toLowerCase() + camelCase.substring(1); + return result; + } +} diff --git a/transitclock/src/main/java/org/transitclock/ipc/data/IpcAvl.java b/transitclock/src/main/java/org/transitclock/ipc/data/IpcAvl.java index 6298cbab5..e7e294146 100644 --- a/transitclock/src/main/java/org/transitclock/ipc/data/IpcAvl.java +++ b/transitclock/src/main/java/org/transitclock/ipc/data/IpcAvl.java @@ -24,6 +24,7 @@ import org.transitclock.db.structs.AvlReport; import org.transitclock.db.structs.AvlReport.AssignmentType; +import org.transitclock.db.structs.OccupancyStatus; import org.transitclock.utils.Geo; import org.transitclock.utils.Time; @@ -47,8 +48,10 @@ public class IpcAvl implements Serializable { private final String driverId; private final String licensePlate; private final int passengerCount; + private final IpcOccupancyStatus occupancyStatus; + + private static final long serialVersionUID = 2506303490106709587L; - private static final long serialVersionUID = 2506303490106709586L; /********************** Member Functions **************************/ @@ -69,7 +72,7 @@ public class IpcAvl implements Serializable { public IpcAvl(String vehicleId, long time, float latitude, float longitude, float speed, float heading, String source, String assignmentId, AssignmentType assignmentType, String driverId, - String licensePlate, int passengerCount) { + String licensePlate, int passengerCount, IpcOccupancyStatus occupancyStatus) { this.vehicleId = vehicleId; this.time = time; this.latitude = latitude; @@ -82,10 +85,11 @@ public IpcAvl(String vehicleId, long time, float latitude, float longitude, this.driverId = driverId; this.licensePlate = licensePlate; this.passengerCount = passengerCount; + this.occupancyStatus = occupancyStatus; } /** - * @param lastAvlReport + * copy from AvlReport */ public IpcAvl(AvlReport a) { this.vehicleId = a.getVehicleId(); @@ -100,6 +104,12 @@ public IpcAvl(AvlReport a) { this.driverId = a.getDriverId(); this.licensePlate = a.getLicensePlate(); this.passengerCount = a.getPassengerCount(); + this.occupancyStatus = toIpcOccupancyStatus(a.getOccupancyStatus()); + } + + private IpcOccupancyStatus toIpcOccupancyStatus(OccupancyStatus occupancyStatus) { + if (occupancyStatus == null) return null; + return IpcOccupancyStatus.toEnum(occupancyStatus.valueOf()); } /* @@ -120,7 +130,8 @@ private static class SerializationProxy implements Serializable { private String driverId; private String licensePlate; private int passengerCount; - + private IpcOccupancyStatus occupancyStatus; + private static final long serialVersionUID = 6220698347690060245L; private static final short serializationVersion = 0; @@ -140,6 +151,7 @@ private SerializationProxy(IpcAvl avl) { this.driverId = avl.driverId; this.licensePlate = avl.licensePlate; this.passengerCount = avl.passengerCount; + this.occupancyStatus = avl.occupancyStatus; } /* @@ -163,6 +175,7 @@ private void writeObject(java.io.ObjectOutputStream stream) stream.writeObject(driverId); stream.writeObject(licensePlate); stream.writeInt(passengerCount); + stream.writeObject(occupancyStatus); } /* @@ -175,7 +188,7 @@ private void writeObject(java.io.ObjectOutputStream stream) private Object readResolve() { return new IpcAvl(vehicleId, time, latitude, longitude, speed, heading, source, assignmentId, assignmentType, driverId, - licensePlate, passengerCount); + licensePlate, passengerCount, occupancyStatus); } /* @@ -203,6 +216,7 @@ private void readObject(java.io.ObjectInputStream stream) driverId = (String) stream.readObject(); licensePlate = (String) stream.readObject(); passengerCount = stream.readInt(); + occupancyStatus = (IpcOccupancyStatus) stream.readObject(); } } @@ -277,6 +291,8 @@ public int getPassengerCount() { return passengerCount; } + public IpcOccupancyStatus getOccupancyStatus() { return occupancyStatus; } + @Override public String toString() { return "IpcAvl [vehicleId=" + vehicleId @@ -290,7 +306,8 @@ public String toString() { + ", assignmentType=" + assignmentType + ", driverId=" + driverId + ", licensePlate=" + licensePlate - + ", passengerCount=" + passengerCount + + ", passengerCount=" + passengerCount + + ", occupancyStatus=" + occupancyStatus + "]"; } diff --git a/transitclock/src/main/java/org/transitclock/ipc/data/IpcOccupancyStatus.java b/transitclock/src/main/java/org/transitclock/ipc/data/IpcOccupancyStatus.java new file mode 100644 index 000000000..e13463b1a --- /dev/null +++ b/transitclock/src/main/java/org/transitclock/ipc/data/IpcOccupancyStatus.java @@ -0,0 +1,159 @@ +/* + * This file is part of Transitime.org + * + * Transitime.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License (GPL) as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * Transitime.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Transitime.org . If not, see . + */ +package org.transitclock.ipc.data; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.Serializable; + +/** + * this mirrors GTFS-RT's occupancyStatus (2016 version): + * https://developers.google.com/transit/gtfs-realtime/reference/OccupancyStatus-vp + *

+ * Constants proposed here: + * https://github.com/OneBusAway/onebusaway-application-modules/issues/121 + *

+ * Borrowed from https://github.com/OneBusAway/onebusaway-application-modules/onebusaway-realtime-api + */ +public enum IpcOccupancyStatus implements Serializable { + + /** + * proposed addition + */ + UNKNOWN(-1), + /** + * The vehicle is considered empty by most measures, has few or no passengers + * onboard, and is accepting passengers. + */ + EMPTY(0), + /** + * The vehicle has a large percentage of seats available. What percentage of + * free seats out of the total seats available is large enough to fall into + * this category is determined by the producer. + */ + MANY_SEATS_AVAILABLE(1), + /** + * The vehicle has a small percentage of seats available. What percentage + * of free seats out of the total seats available is small enough to fall + * into this category is determined by the producer. + */ + FEW_SEATS_AVAILABLE(2), + /** + * The vehicle can accommodate only standing passengers. + */ + STANDING_ROOM_ONLY(3), + /** + * The vehicle can accommodate only standing passengers but has limited + * space for them. + */ + CRUSHED_STANDING_ROOM_ONLY(4), + /** + * The vehicle is considered full by most measures but may still be allowing + * passengers to board. + */ + FULL(5), + /** + * The vehicle is not accepting passengers. + */ + NOT_ACCEPTING_PASSENGERS(6); + + private static Logger _log = LoggerFactory.getLogger(IpcOccupancyStatus.class); + private int _status; + private static final long serialVersionUID = 2506303490106709595L; + + IpcOccupancyStatus() { + _status = -1; + } + + IpcOccupancyStatus(int status) { + _status = status; + } + + public int valueOf() { + return _status; + } + + public static boolean contains(String status) { + for (IpcOccupancyStatus IpcOccupancyStatus : values()) { + if (IpcOccupancyStatus.name().equalsIgnoreCase(status)) { + return true; + } + } + return false; + } + + public String toString() { + return toCamelCase(this.name()); + } + + public static IpcOccupancyStatus toEnum(int status) { + if (status == UNKNOWN.valueOf() || status < 0) + return UNKNOWN; + if (status == EMPTY.valueOf()) + return EMPTY; + if (status == MANY_SEATS_AVAILABLE.valueOf()) + return MANY_SEATS_AVAILABLE; + if (status == FEW_SEATS_AVAILABLE.valueOf()) + return FEW_SEATS_AVAILABLE; + if (status == STANDING_ROOM_ONLY.valueOf()) + return STANDING_ROOM_ONLY; + if (status == CRUSHED_STANDING_ROOM_ONLY.valueOf()) + return CRUSHED_STANDING_ROOM_ONLY; + if (status == FULL.valueOf()) + return FULL; + if (status == NOT_ACCEPTING_PASSENGERS.valueOf()) { + _log.warn("Occupancy Status set to NotAcceptingPassengers"); + return NOT_ACCEPTING_PASSENGERS; + } + throw new IllegalArgumentException("unexpected value " + status); + } + + public static IpcOccupancyStatus toEnum(double rid) { + int status; + if (rid < 0.0) { + status = -1; + } else if (rid == 0.0) { + status = 0; + } else if (rid <= 25.0) { + status = 1; + } else if (rid <= 50.0) { + status = 2; + } else if (rid <= 75.0) { + status = 3; + } else if (rid <= 90.0) { + status = 4; + } else if (rid <= 100.0) { + status = 5; + } else { + status = 6; + } + return IpcOccupancyStatus.toEnum(status); + } + + private String toCamelCase(String upperCase) { + if (upperCase == null || upperCase.length() == 0) return upperCase; + String[] parts = upperCase.split("_"); + StringBuffer camelCase = new StringBuffer(); + for (String part : parts) { + camelCase.append(part.substring(0, 1).toUpperCase()); + camelCase.append(part.substring(1).toLowerCase()); + } + String result = camelCase.substring(0, 1).toLowerCase() + camelCase.substring(1); + return result; + } +} diff --git a/transitclock/src/main/java/org/transitclock/ipc/data/IpcPrediction.java b/transitclock/src/main/java/org/transitclock/ipc/data/IpcPrediction.java index 4b5ff34e5..1f9aa88fc 100644 --- a/transitclock/src/main/java/org/transitclock/ipc/data/IpcPrediction.java +++ b/transitclock/src/main/java/org/transitclock/ipc/data/IpcPrediction.java @@ -24,6 +24,7 @@ import org.transitclock.applications.Core; import org.transitclock.db.structs.AvlReport; +import org.transitclock.db.structs.OccupancyStatus; import org.transitclock.db.structs.Trip; import org.transitclock.ipc.data.IpcPrediction.ArrivalOrDeparture; import org.transitclock.utils.StringUtils; @@ -81,6 +82,7 @@ public class IpcPrediction implements Serializable { private final boolean isArrival; private final Integer delay; private boolean isCanceled; + private final IpcOccupancyStatus occupancyStatus; public boolean isCanceled() { return isCanceled; @@ -93,7 +95,7 @@ public boolean isCanceled() { // when creating PredictionsForRouteStop object. private final Trip trip; - private static final long serialVersionUID = 7264507678733060173L; + private static final long serialVersionUID = 7264507678733060174L; public enum ArrivalOrDeparture {ARRIVAL, DEPARTURE}; @@ -121,7 +123,6 @@ public enum ArrivalOrDeparture {ARRIVAL, DEPARTURE}; * @param atEndOfTrip * True if prediction for last stop of trip, which means likely * not useful to user - * @param predictionAffectedByWaitStop * @param isDelayed * @param lateAndSubsequentTripSoMarkAsUncertain * @param arrivalOrDeparture @@ -164,6 +165,7 @@ public IpcPrediction(AvlReport avlReport, String stopId, int gtfsStopSeq, this.driverId = avlReport.getDriverId(); this.passengerCount = (short) avlReport.getPassengerCount(); this.passengerFullness = avlReport.getPassengerFullness(); + this.occupancyStatus = toIpcOccupancyStatus(avlReport.getOccupancyStatus()); this.isDelayed = isDelayed; this.lateAndSubsequentTripSoMarkAsUncertain = lateAndSubsequentTripSoMarkAsUncertain; @@ -174,6 +176,11 @@ public IpcPrediction(AvlReport avlReport, String stopId, int gtfsStopSeq, this.isCanceled=isCanceled; } + private IpcOccupancyStatus toIpcOccupancyStatus(OccupancyStatus occupancyStatus) { + if (occupancyStatus == null) return null; + return IpcOccupancyStatus.toEnum(occupancyStatus.valueOf()); + } + /** * Constructor used for when deserializing a proxy object. Declared private * because only used internally by the proxy class. @@ -186,7 +193,7 @@ private IpcPrediction(String vehicleId, String routeId, String stopId, boolean affectedByWaitStop, String driverId, short passengerCount, float passengerFullness, boolean isDelayed, - boolean lateAndSubsequentTripSoMarkAsUncertain, boolean isArrival, Integer delay, Long freqStartTime, int tripCounter,boolean isCanceled) { + boolean lateAndSubsequentTripSoMarkAsUncertain, boolean isArrival, Integer delay, Long freqStartTime, int tripCounter,boolean isCanceled, IpcOccupancyStatus occupancyStatus) { this.vehicleId = vehicleId; this.routeId = routeId; @@ -209,6 +216,7 @@ private IpcPrediction(String vehicleId, String routeId, String stopId, this.driverId = driverId; this.passengerCount = passengerCount; this.passengerFullness = passengerFullness; + this.occupancyStatus = occupancyStatus; this.isDelayed = isDelayed; this.lateAndSubsequentTripSoMarkAsUncertain = lateAndSubsequentTripSoMarkAsUncertain; @@ -246,6 +254,7 @@ private static class SerializationProxy implements Serializable { private String driverId; private short passengerCount; private float passengerFullness; + private IpcOccupancyStatus occupancyStatus; private boolean isDelayed; private boolean lateAndSubsequentTripSoMarkAsUncertain; private boolean isArrival; @@ -281,6 +290,7 @@ private SerializationProxy(IpcPrediction p) { this.driverId = p.driverId; this.passengerCount = p.passengerCount; this.passengerFullness = p.passengerFullness; + this.occupancyStatus = p.occupancyStatus; this.isDelayed = p.isDelayed; this.lateAndSubsequentTripSoMarkAsUncertain = p.lateAndSubsequentTripSoMarkAsUncertain; @@ -330,7 +340,7 @@ private void writeObject(java.io.ObjectOutputStream stream) stream.writeObject(delay); stream.writeBoolean(isCanceled); - + stream.writeObject(occupancyStatus); } /* @@ -377,6 +387,7 @@ private void readObject(java.io.ObjectInputStream stream) delay = (Integer) stream.readObject(); isCanceled=stream.readBoolean(); + occupancyStatus = (IpcOccupancyStatus) stream.readObject(); } /* @@ -391,7 +402,7 @@ private Object readResolve() { atEndOfTrip, schedBasedPred, avlTime, creationTime, tripStartEpochTime, affectedByWaitStop, driverId, passengerCount, passengerFullness, isDelayed, - lateAndSubsequentTripSoMarkAsUncertain, isArrival, delay, freqStartTime, tripCounter,isCanceled); + lateAndSubsequentTripSoMarkAsUncertain, isArrival, delay, freqStartTime, tripCounter,isCanceled, occupancyStatus); } } @@ -445,6 +456,7 @@ public String toString() { + (!Float.isNaN(passengerFullness) ? ", psngrFullness=" + StringUtils.twoDigitFormat(passengerFullness) : "") + ("isCanceled= "+isCanceled) + + ", occupancyStatus=" + occupancyStatus + "]"; } @@ -546,6 +558,8 @@ public boolean isPassengerCountValid() { return passengerCount >= 0; } + public IpcOccupancyStatus getOccupancyStatus() { return occupancyStatus; } + public boolean isDelayed() { return isDelayed; } diff --git a/transitclock/src/main/java/org/transitclock/ipc/data/IpcVehicle.java b/transitclock/src/main/java/org/transitclock/ipc/data/IpcVehicle.java index 422da6ca1..296ecc043 100644 --- a/transitclock/src/main/java/org/transitclock/ipc/data/IpcVehicle.java +++ b/transitclock/src/main/java/org/transitclock/ipc/data/IpcVehicle.java @@ -199,7 +199,6 @@ public IpcVehicle(VehicleState vs) { * @param blockId * @param blockAssignmentMethod * @param avl - * @param pathHeading * @param routeId * @param routeShortName * @param routeName @@ -626,7 +625,7 @@ public static void main(String args[]) { IpcAvl avl = new IpcAvl("avlVehicleId", 10, 1.23f, 4.56f, 0.0f, 0.0f, null, "block", AssignmentType.BLOCK_ID, "driver", "license", - 0); + 0, null); IpcVehicle v = new IpcVehicle("blockId", BlockAssignmentMethod.AVL_FEED_BLOCK_ASSIGNMENT, avl, diff --git a/transitclock/src/main/java/org/transitclock/ipc/data/IpcVehicleComplete.java b/transitclock/src/main/java/org/transitclock/ipc/data/IpcVehicleComplete.java index 0dfbb42f1..ce520b0ae 100644 --- a/transitclock/src/main/java/org/transitclock/ipc/data/IpcVehicleComplete.java +++ b/transitclock/src/main/java/org/transitclock/ipc/data/IpcVehicleComplete.java @@ -27,6 +27,7 @@ import org.transitclock.core.SpatialMatch; import org.transitclock.core.TemporalDifference; import org.transitclock.core.VehicleState; +import org.transitclock.db.structs.OccupancyStatus; import org.transitclock.db.structs.Trip; import org.transitclock.utils.Geo; import org.transitclock.utils.Time; @@ -51,8 +52,9 @@ public class IpcVehicleComplete extends IpcVehicleGtfsRealtime { private final Double distanceOfNextStopFromTripStart; private final Double distanceAlongTrip; private double headway; + private final IpcOccupancyStatus occupancyStatus; - private static final long serialVersionUID = 8154105842499551461L; + private static final long serialVersionUID = 8154105842499551462L; /********************** Member Functions **************************/ @@ -88,6 +90,7 @@ public IpcVehicleComplete(VehicleState vs) { this.distanceOfNextStopFromTripStart = sumOfStopPathLengths; this.distanceAlongTrip = sumOfStopPathLengths - this.distanceToNextStop; + this.occupancyStatus = toIpcOccupancyStatus(vs.getAvlReport().getOccupancyStatus()); if(vs.getHeadway()!=null) { this.headway=vs.getHeadway().getHeadway(); @@ -101,9 +104,15 @@ public IpcVehicleComplete(VehicleState vs) { this.distanceToNextStop =null; //Double.NaN; this.distanceOfNextStopFromTripStart =null;// Double.NaN; this.distanceAlongTrip =null; // Double.NaN; + this.occupancyStatus = null; } } - + + protected IpcOccupancyStatus toIpcOccupancyStatus(OccupancyStatus occupancyStatus) { + if (occupancyStatus == null) return null; + return IpcOccupancyStatus.toEnum(occupancyStatus.valueOf()); + } + /** * Constructor used for when deserializing a proxy object. * @@ -127,7 +136,6 @@ public IpcVehicleComplete(VehicleState vs) { * @param nextStopId * @param nextStopName * @param vehicleType - * @param tripStartDateStr * @param atStop * @param atOrNextStopId * @param atOrNextGtfsStopSeq @@ -148,9 +156,8 @@ private IpcVehicleComplete(String blockId, long tripStartEpochTime, boolean atStop, String atOrNextStopId, Integer atOrNextGtfsStopSeq, String originStopId, String destinationId, Double distanceToNextStop, - Double distanceOfNextStopFromTripStart, Double distanceAlongTrip, long freqStartTime, IpcHoldingTime holdingTime, double predictedLatitude, double predictedLongitude,boolean isCanceled, - double headway) { + double headway, IpcOccupancyStatus occupancyStatus) { super(blockId, blockAssignmentMethod, avl, pathHeading, routeId, routeShortName, routeName, tripId, tripPatternId, isTripUnscheduled, directionId, headsign, @@ -166,6 +173,7 @@ private IpcVehicleComplete(String blockId, this.distanceOfNextStopFromTripStart = distanceOfNextStopFromTripStart; this.distanceAlongTrip = distanceAlongTrip; this.headway=headway; + this.occupancyStatus = occupancyStatus; } /* @@ -181,6 +189,7 @@ protected static class CompleteVehicleSerializationProxy private Double distanceOfNextStopFromTripStart; private Double distanceAlongTrip; private double headway; + private IpcOccupancyStatus occupancyStatus; private static final short currentSerializationVersion = 0; private static final long serialVersionUID = 6982458672576764027L; @@ -193,6 +202,7 @@ private CompleteVehicleSerializationProxy(IpcVehicleComplete v) { this.distanceOfNextStopFromTripStart = v.distanceOfNextStopFromTripStart; this.distanceAlongTrip = v.distanceAlongTrip; this.headway=v.headway; + this.occupancyStatus = v.occupancyStatus; } /* @@ -215,6 +225,7 @@ protected void writeObject(java.io.ObjectOutputStream stream) stream.writeObject(distanceOfNextStopFromTripStart); stream.writeObject(distanceAlongTrip); stream.writeDouble(headway); + stream.writeObject(occupancyStatus); } /* @@ -244,6 +255,7 @@ protected void readObject(java.io.ObjectInputStream stream) distanceAlongTrip =(Double) stream.readObject(); isCanceled=stream.readBoolean(); headway=stream.readDouble(); + occupancyStatus = (IpcOccupancyStatus) stream.readObject(); } /* @@ -263,7 +275,7 @@ private Object readResolve() { distanceToNextStop, distanceOfNextStopFromTripStart, distanceAlongTrip, freqStartTime, holdingTime, predictedLatitude, predictedLongitude,isCanceled, - headway); + headway, occupancyStatus); } @@ -310,6 +322,7 @@ public double getHeadway() { return headway; } + public IpcOccupancyStatus getOccupancyStatus() { return occupancyStatus; } @Override public String toString() { @@ -349,7 +362,8 @@ public String toString() { + ", distanceOfNextStopFromTripStart=" + Geo.distanceFormat(distanceOfNextStopFromTripStart) + ", distanceAlongTrip=" - + Geo.distanceFormat(distanceAlongTrip) + + Geo.distanceFormat(distanceAlongTrip) + + ", occupancyStatus=" + occupancyStatus + "]"; } diff --git a/transitclockApi/src/main/java/org/transitclock/api/data/ApiPrediction.java b/transitclockApi/src/main/java/org/transitclock/api/data/ApiPrediction.java index 57c3becfe..681abd35d 100644 --- a/transitclockApi/src/main/java/org/transitclock/api/data/ApiPrediction.java +++ b/transitclockApi/src/main/java/org/transitclock/api/data/ApiPrediction.java @@ -20,6 +20,7 @@ import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlRootElement; +import org.transitclock.ipc.data.IpcOccupancyStatus; import org.transitclock.ipc.data.IpcPrediction; import org.transitclock.utils.Time; @@ -83,6 +84,9 @@ public class ApiPrediction { @XmlAttribute(name = "passengerCount") private String passengerCount; + @XmlAttribute(name = "occupancyStatus") + private IpcOccupancyStatus occupancyStatus; + @XmlAttribute(name = "isDeparture") private String isDepartureDuplicate; //same field different name @@ -131,7 +135,9 @@ public ApiPrediction(IpcPrediction prediction) { // is not valid since will then be null if (prediction.isPassengerCountValid()) passengerCount = String.valueOf(prediction.getPassengerCount()); - + + occupancyStatus = prediction.getOccupancyStatus(); + // Only set if true so only output for rare case if (prediction.isDelayed()) isDelayed = true; diff --git a/transitclockQuickStart/src/test/resources/hsql_hibernate.cfg.xml b/transitclockQuickStart/src/test/resources/hsql_hibernate.cfg.xml index 954c2f151..1c5cdd1f3 100644 --- a/transitclockQuickStart/src/test/resources/hsql_hibernate.cfg.xml +++ b/transitclockQuickStart/src/test/resources/hsql_hibernate.cfg.xml @@ -54,17 +54,12 @@ setting batch_size to 25 actually hurt performance by a few percent. Probably much more important when db is remote and network traffic could bog down the thread that is writing. --> -<<<<<<< HEAD:transitime/src/main/resources/postgres_hibernate.cfg.xml - 25 - -======= 1 100 true true true update ->>>>>>> 336ae7a8c5ba9942d8023817d7f7d64ffef019da:transitimeQuickStart/src/test/resources/hsql_hibernate.cfg.xml