Package org.onebusaway.transit_data_federation.impl.realtime.mybus

Source Code of org.onebusaway.transit_data_federation.impl.realtime.mybus.TimepointPredictionServiceImpl$TimepointPredictionReceiver

/**
* Copyright (C) 2011 Brian Ferris <bdferris@onebusaway.org>
*
* 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.mybus;

import its.SQL.ContentsData;
import its.backbone.sdd.SddReceiver;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.onebusaway.gtfs.model.AgencyAndId;
import org.onebusaway.realtime.api.TimepointPredictionRecord;
import org.onebusaway.realtime.api.VehicleLocationListener;
import org.onebusaway.realtime.api.VehicleLocationRecord;
import org.onebusaway.transit_data_federation.services.blocks.BlockCalendarService;
import org.onebusaway.transit_data_federation.services.blocks.BlockInstance;
import org.onebusaway.transit_data_federation.services.transit_graph.BlockEntry;
import org.onebusaway.transit_data_federation.services.transit_graph.TransitGraphDao;
import org.onebusaway.transit_data_federation.services.transit_graph.TripEntry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedResource;

@ManagedResource("org.onebusaway.transit_data_federation.impl.realtime.mybus:name=TimepointPredictionServiceImpl")
public class TimepointPredictionServiceImpl {

  private final Logger _log = LoggerFactory.getLogger(TimepointPredictionServiceImpl.class);

  private static final String TIMEPOINT_PREDICTION_SERVER_NAME = "carpool.its.washington.edu";

  private static final int TIMEPOINT_PREDICTION_SERVER_PORT = 9002;

  private TimepointPredictionReceiver _receiver;

  private String _serverName = TIMEPOINT_PREDICTION_SERVER_NAME;

  private int _serverPort = TIMEPOINT_PREDICTION_SERVER_PORT;

  private File _tripIdMappingFile;

  private Map<String, String> _tripIdMapping = new HashMap<String, String>();

  private List<String> _agencyIds = Arrays.asList("1", "40");

  private long _predictionCount = 0;
 
  private long _unmappedTripIdCount = 0;
 
  private long _noPredictionCount = 0;

  private long _mappedTripIdCount = 0;

  private BlockCalendarService _blockCalendarService;

  private TransitGraphDao _transitGraph;

  private VehicleLocationListener _vehicleLocationListener;

  private boolean _includeTimepointPredictionRecords = false;

  public void setServerName(String name) {
    _serverName = name;
  }

  public void setServerPort(int port) {
    _serverPort = port;
  }

  public void setTripIdMappingPath(File tripIdMapping) {
    _tripIdMappingFile = tripIdMapping;
  }

  public void setTripIdMapping(Map<String, String> tripIdMapping) {
    _tripIdMapping = tripIdMapping;
  }

  public void setAgencyId(String agencyId) {
    _agencyIds = Arrays.asList(agencyId);
  }

  public void setAgencyIds(List<String> agencyIds) {
    _agencyIds = agencyIds;
  }

  public void setIncludeTimepointPredictionRecords(
      boolean includeTimepointPredictionRecords) {
    _includeTimepointPredictionRecords = includeTimepointPredictionRecords;
  }

  @Autowired
  public void setTransitGraphDao(TransitGraphDao transitGraph) {
    _transitGraph = transitGraph;
  }

  @Autowired
  public void setBlockCalendarService(BlockCalendarService blockCalendarService) {
    _blockCalendarService = blockCalendarService;
  }

  @Autowired
  public void setVehicleLocationListener(
      VehicleLocationListener vehicleLocationListener) {
    _vehicleLocationListener = vehicleLocationListener;
  }

  /****
   *
   ****/

  @PostConstruct
  public void startup() {
    try {
      loadTripIdMappingFromFile();

      _log.info("Starting timepoint receiver");
      if (!_tripIdMapping.isEmpty())
        System.out.println("  tripIdMappings=" + _tripIdMapping.size());
      _receiver = new TimepointPredictionReceiver(_serverName, _serverPort);
      _receiver.start();

    } catch (IOException ex) {
      _log.error("error starting transit prediction data receiver", ex);
    }
  }

  @PreDestroy
  public void shutdown() {
    _receiver.stop();
  }

  /****
   * Statistics Methods
   ****/

  @ManagedAttribute
  public long getPredictionCount() {
    return _predictionCount;
  }
 
  @ManagedAttribute
  public long getUnmappedTripIdCount() {
    return _unmappedTripIdCount;
  }
 
  @ManagedAttribute
  public long getNoPredictionCount() {
    return _noPredictionCount;
  }

  @ManagedAttribute
  public long getMappedTripIdCount() {
    return _mappedTripIdCount;
  }

  /*****
   *
   ****/

  private void loadTripIdMappingFromFile() throws FileNotFoundException,
      IOException {

    if (_tripIdMappingFile == null || !_tripIdMappingFile.exists())
      return;

    BufferedReader reader = new BufferedReader(new FileReader(
        _tripIdMappingFile));
    String line = null;

    while ((line = reader.readLine()) != null) {
      int index = line.indexOf(' ');
      if (index == -1)
        throw new IllegalStateException("bad timepoint mapping line: " + line);
      String fromTripId = line.substring(0, index);
      String toTripId = line.substring(index + 1);
      _tripIdMapping.put(fromTripId, toTripId);
    }
  }

  private void parsePredictions(Hashtable<?, ?> ht) {

    Map<AgencyAndId, List<TimepointPrediction>> predictionsByBlockId = new HashMap<AgencyAndId, List<TimepointPrediction>>();

    if (ht.containsKey("PREDICTIONS")) {
      ContentsData data = (ContentsData) ht.get("PREDICTIONS");
      data.resetRowIndex();
      while (data.next()) {

        _predictionCount++;

        String agencyId = data.getString(0);

        // We override the agency id in the stream, since it's usually 0
        if (!_agencyIds.isEmpty())
          agencyId = _agencyIds.get(0);

        String tripId = data.getString(2);

        TripEntry tripEntry = getTripEntryForId(agencyId, tripId);

        if (tripEntry == null) {
          _unmappedTripIdCount++;
          continue;
        }

        BlockEntry block = tripEntry.getBlock();

        TimepointPrediction record = new TimepointPrediction();

        record.setBlockId(block.getId());
        record.setTripId(tripEntry.getId());

        String tripAgencyId = tripEntry.getId().getAgencyId();
        record.setVehicleId(new AgencyAndId(tripAgencyId, data.getString(6)));
        record.setScheduleDeviation(data.getInt(14));
        record.setTimepointId(new AgencyAndId(agencyId, data.getString(3)));
        record.setTimepointScheduledTime(data.getInt(4));
        record.setTimepointPredictedTime(data.getInt(13));
        record.setTimeOfPrediction(data.getInt(9));
        record.setPredictorType(data.getString(12));
       
        // Indicates that we don't have any real-time predictions for this
        // record
        if (record.getTimepointPredictedTime() == -1 || ! "p".equals(record.getPredictorType())) {
          _noPredictionCount++;
          continue;
        }

        List<TimepointPrediction> records = predictionsByBlockId.get(record.getBlockId());
        if (records == null) {
          records = new ArrayList<TimepointPrediction>();
          predictionsByBlockId.put(record.getBlockId(), records);
        }

        _mappedTripIdCount++;
        records.add(record);
      }
    }

    if (predictionsByBlockId.isEmpty())
      return;

    long t = System.currentTimeMillis();
    long timeFrom = t - 30 * 60 * 1000;
    long timeTo = t + 30 * 60 * 1000;

    List<VehicleLocationRecord> records = new ArrayList<VehicleLocationRecord>();

    for (List<TimepointPrediction> recordsForBlock : predictionsByBlockId.values()) {
      VehicleLocationRecord record = getBestScheduleAdherenceRecord(recordsForBlock);
      List<BlockInstance> instances = _blockCalendarService.getActiveBlocks(
          record.getBlockId(), timeFrom, timeTo);
      // TODO : We currently assume that a block won't overlap with itself
      if (instances.size() != 1)
        continue;

      BlockInstance instance = instances.get(0);
      record.setServiceDate(instance.getServiceDate());

      records.add(record);
    }

    _vehicleLocationListener.handleVehicleLocationRecords(records);
  }

  private VehicleLocationRecord getBestScheduleAdherenceRecord(
      List<TimepointPrediction> recordsForBlock) {

    TimepointPrediction best = getBestTimepointPrediction(recordsForBlock);

    VehicleLocationRecord r = new VehicleLocationRecord();
    r.setBlockId(best.getBlockId());
    r.setTimeOfRecord(System.currentTimeMillis());
    r.setTimeOfLocationUpdate(r.getTimeOfRecord());
    r.setScheduleDeviation(best.getScheduleDeviation());

    if (_includeTimepointPredictionRecords) {
      TimepointPredictionRecord tpr = new TimepointPredictionRecord();
      tpr.setTimepointId(best.getTimepointId());
      tpr.setTimepointPredictedTime(best.getTimepointPredictedTime());
      tpr.setTimepointScheduledTime(best.getTimepointScheduledTime());
      r.setTimepointPredictions(Arrays.asList(tpr));
    }

    r.setTripId(best.getTripId());
    r.setVehicleId(best.getVehicleId());
    return r;
  }

  /**
   * We want the SECOND record whose timepoint has not already been passed.
   *
   * @param recordsForTrip
   * @return
   */
  private TimepointPrediction getBestTimepointPrediction(
      List<TimepointPrediction> recordsForTrip) {

    TimepointPrediction prev = null;
    int prevDelta = -1;

    for (TimepointPrediction record : recordsForTrip) {

      int delta = record.getTimepointPredictedTime()
          - record.getTimeOfPrediction();

      if (prev != null) {
        if (!prev.getTimepointId().equals(record.getTimepointId())
            && prevDelta >= 0 && delta > prevDelta)
          break;
      }

      prev = record;
      prevDelta = delta;
    }

    return prev;
  }

  private TripEntry getTripEntryForId(String agencyId, String tripId) {

    String mappedTripId = _tripIdMapping.get(tripId);
    if (mappedTripId != null)
      tripId = mappedTripId;

    for (String aid : _agencyIds) {
      AgencyAndId fullTripId = new AgencyAndId(aid, tripId);
      TripEntry tripEntry = _transitGraph.getTripEntryForId(fullTripId);
      if (tripEntry != null)
        return tripEntry;
    }

    return null;
  }

  private class TimepointPredictionReceiver extends SddReceiver {

    public TimepointPredictionReceiver(String serverName, int serverPort)
        throws IOException {
      super(serverName, serverPort);
    }

    @Override
    public void extractedDataReceived(
        @SuppressWarnings("rawtypes") Hashtable ht, String serialNum) {
      super.extractedDataReceived(ht, serialNum);

      try {
        parsePredictions(ht);
      } catch (Throwable ex) {
        _log.error("error parsing predictions from sdd data stream", ex);
      }
    }

  }

}
TOP

Related Classes of org.onebusaway.transit_data_federation.impl.realtime.mybus.TimepointPredictionServiceImpl$TimepointPredictionReceiver

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.