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
+ * 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
-