/** * Copyright (C) 2011 Brian Ferris <bdferris@onebusaway.org> * Copyright (C) 2015 University of South Florida * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.onebusaway.transit_data_federation.impl.realtime; import javax.persistence.AttributeOverride; import javax.persistence.AttributeOverrides; import javax.persistence.Column; import javax.persistence.Embedded; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table; import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.annotations.Index; import org.hibernate.annotations.Parameter; import org.hibernate.annotations.Type; import org.onebusaway.geospatial.model.CoordinatePoint; import org.onebusaway.gtfs.model.AgencyAndId; import org.onebusaway.realtime.api.EVehiclePhase; /** * A block location record is a database-serializable record that captures the * real-time position and schedule deviation for a transit vehicle at a * particular point in time. The record includes trip instance data and vehicle * id where available. * * This class is mean for internal use. * * @author bdferris */ @Entity @Table(name = "transit_data_block_location_records") @org.hibernate.annotations.Table(appliesTo = "transit_data_block_location_records", indexes = { @Index(name = "vehicle_and_time", columnNames = { "vehicle_agencyId", "vehicle_id", "time"}), @Index(name = "vehicle_and_serviceDate", columnNames = { "vehicle_agencyId", "vehicle_id", "serviceDate"})}) @org.hibernate.annotations.Entity(mutable = false) @Cache(usage = CacheConcurrencyStrategy.READ_ONLY) public class BlockLocationRecord { @Id @GeneratedValue private final int id = 0; @Embedded @AttributeOverrides({ @AttributeOverride(name = "agencyId", column = @Column(name = "block_agencyId", length = 50)), @AttributeOverride(name = "id", column = @Column(name = "block_id"))}) private final AgencyAndId blockId; @Embedded @AttributeOverrides({ @AttributeOverride(name = "agencyId", column = @Column(name = "trip_agencyId", length = 50)), @AttributeOverride(name = "id", column = @Column(name = "trip_id"))}) private final AgencyAndId tripId; private final long serviceDate; private final long time; @Column(nullable = true) private final Double scheduleDeviation; @Column(nullable = true) private final Double distanceAlongBlock; @Column(nullable = true) private final Double distanceAlongTrip; @Column(nullable = true) private final Double locationLat; @Column(nullable = true) private final Double locationLon; @Column(nullable = true) private final Double orientation; @Embedded @AttributeOverrides({ @AttributeOverride(name = "agencyId", column = @Column(name = "timepoint_agencyId", length = 50)), @AttributeOverride(name = "id", column = @Column(name = "timepoint_id"))}) private final AgencyAndId timepointId; private final long timepointScheduledTime; private final long timepointPredictedArrivalTime; private final long timepointPredictedDepartureTime; /** * Custom Hibernate mapping so that the vehicle phase enum gets mapped to a * string as opposed to an integer, allowing for safe expansion of the enum in * the future and more legibility in the raw SQL. Additionally, the phase * string can be a little shorter than the default length. */ @Type(type = "org.onebusaway.container.hibernate.EnumUserType", parameters = {@Parameter(name = "enumClassName", value = "org.onebusaway.realtime.api.EVehiclePhase")}) @Column(length = 50) private final EVehiclePhase phase; private final String status; @Embedded @AttributeOverrides({ @AttributeOverride(name = "agencyId", column = @Column(name = "vehicle_agencyId", length = 50)), @AttributeOverride(name = "id", column = @Column(name = "vehicle_id"))}) private final AgencyAndId vehicleId; public static Builder builder() { return new Builder(); } public BlockLocationRecord() { blockId = null; tripId = null; serviceDate = 0; time = 0; scheduleDeviation = null; distanceAlongBlock = null; distanceAlongTrip = null; locationLat = null; locationLon = null; orientation = null; timepointId = null; timepointScheduledTime = 0; timepointPredictedArrivalTime = -1; timepointPredictedDepartureTime = -1; phase = null; status = null; vehicleId = null; } private BlockLocationRecord(Builder builder) { this.blockId = builder.blockId; this.tripId = builder.tripId; this.serviceDate = builder.serviceDate; this.time = builder.time; this.scheduleDeviation = builder.scheduleDeviation; this.distanceAlongBlock = builder.distanceAlongBlock; this.distanceAlongTrip = builder.distanceAlongTrip; this.locationLat = builder.locationLat; this.locationLon = builder.locationLon; this.orientation = builder.orientation; this.timepointId = builder.timepointId; this.timepointScheduledTime = builder.timepointScheduledTime; this.timepointPredictedArrivalTime = builder.timepointPredictedArrivalTime; this.timepointPredictedDepartureTime = builder.timepointPredictedDepartureTime; this.phase = builder.phase; this.status = builder.status; this.vehicleId = builder.vehicleId; } /** * @return a generated numeric id for this record */ public int getId() { return id; } /** * @return the block id of the transit trip */ public AgencyAndId getBlockId() { return blockId; } /** * @return the trip id of the transit trip */ public AgencyAndId getTripId() { return tripId; } /** * @return the service date for the trip instance (Unix-time) */ public long getServiceDate() { return serviceDate; } /** * @return the time the record was recorded (Unix-time) */ public long getTime() { return time; } public boolean isScheduleDeviationSet() { return scheduleDeviation != null; } /** * @return schedule deviation, in seconds, (+deviation is late, -deviation is * early) */ public Double getScheduleDeviation() { return scheduleDeviation; } public boolean isDistanceAlongBlockSet() { return distanceAlongBlock != null; } /** * @return the distance traveled along the block */ public Double getDistanceAlongBlock() { return distanceAlongBlock; } public Double getDistanceAlongTrip() { return distanceAlongTrip; } public boolean isLocationSet() { return locationLat != null && locationLon != null; } public Double getLocationLat() { return locationLat; } public Double getLocationLon() { return locationLon; } public CoordinatePoint getLocation() { if (!isLocationSet()) return null; return new CoordinatePoint(locationLat, locationLon); } public boolean isOrientationSet() { return orientation != null; } /** * In degrees, 0º is East, 90º is North, 180º is West, and 270º is South */ public Double getOrientation() { return orientation; } public AgencyAndId getTimepointId() { return timepointId; } public long getTimepointScheduledTime() { return timepointScheduledTime; } public long getTimepointPredictedArrivalTime() { return timepointPredictedArrivalTime; } public long getTimepointPredictedDepartureTime() { return timepointPredictedDepartureTime; } public EVehiclePhase getPhase() { return phase; } public String getStatus() { return status; } /** * @return the vehicle id of the transit vehicle servicing the trip, when * available */ @Index(name = "vehicleId") public AgencyAndId getVehicleId() { return this.vehicleId; } @Override public String toString() { return "BlockLocationRecord(id=" + id + " blockId=" + blockId + " serviceDate=" + serviceDate + " time=" + time + " scheduleDeviation=" + scheduleDeviation + " vehicleId=" + vehicleId + ")"; } public static class Builder { private AgencyAndId blockId; private AgencyAndId tripId; private long serviceDate; private long time; private Double scheduleDeviation = null; private Double distanceAlongBlock = null; private Double distanceAlongTrip = null; private Double locationLat = null; private Double locationLon = null; private Double orientation = null; private AgencyAndId timepointId; private long timepointScheduledTime; private long timepointPredictedArrivalTime; private long timepointPredictedDepartureTime; private EVehiclePhase phase; private String status; private AgencyAndId vehicleId; public void setBlockId(AgencyAndId blockId) { this.blockId = blockId; } public void setTripId(AgencyAndId tripId) { this.tripId = tripId; } public void setServiceDate(long serviceDate) { this.serviceDate = serviceDate; } public void setTime(long time) { this.time = time; } public void setScheduleDeviation(Double scheduleDeviation) { this.scheduleDeviation = scheduleDeviation; } public void setDistanceAlongBlock(Double distanceAlongBlock) { this.distanceAlongBlock = distanceAlongBlock; } public void setDistanceAlongTrip(Double distanceAlongTrip) { this.distanceAlongTrip = distanceAlongTrip; } public void setLocationLat(Double locationLat) { this.locationLat = locationLat; } public void setLocationLon(Double locationLon) { this.locationLon = locationLon; } public void setLocation(CoordinatePoint location) { if (location == null) { this.locationLat = null; this.locationLon = null; } else { this.locationLat = location.getLat(); this.locationLon = location.getLon(); } } public void setOrientation(Double orientation) { this.orientation = orientation; } public void setTimepointId(AgencyAndId timepointId) { this.timepointId = timepointId; } public void setTimepointScheduledTime(long timepointScheduledTime) { this.timepointScheduledTime = timepointScheduledTime; } public void setTimepointPredictedArrivalTime(long timepointPredictedArrivalTime) { this.timepointPredictedArrivalTime = timepointPredictedArrivalTime; } public void setTimepointPredictedDepartureTime(long timepointPredictedDepartureTime) { this.timepointPredictedDepartureTime = timepointPredictedDepartureTime; } public void setPhase(EVehiclePhase phase) { this.phase = phase; } public void setStatus(String status) { this.status = status; } public void setVehicleId(AgencyAndId vehicleId) { this.vehicleId = vehicleId; } public BlockLocationRecord create() { return new BlockLocationRecord(this); } } }