@Transactional(rollbackFor = Throwable.class)
  @Override
  public void saveOrUpdateRecords(ArchivedInferredLocationRecord... records) {
    List<ArchivedInferredLocationRecord> list =
        new ArrayList<ArchivedInferredLocationRecord>(records.length);
    for (ArchivedInferredLocationRecord record : records) list.add(record);
    _template.saveOrUpdateAll(list);

    // LastKnownRecord
    LinkedHashMap<Integer, CcAndInferredLocationRecord> lastKnownRecords =
        new LinkedHashMap<Integer, CcAndInferredLocationRecord>(records.length);
    for (ArchivedInferredLocationRecord record : records) {
      CcLocationReportRecord cc = findRealtimeRecord(record);
      if (cc != null) {
        CcAndInferredLocationRecord lastKnown = new CcAndInferredLocationRecord(record, cc);
        if (validationService.validateLastKnownRecord(lastKnown)) {
          lastKnownRecords.put(lastKnown.getVehicleId(), lastKnown);
        } else {
          discardRecord(lastKnown);
        }
      }
    }
    _template.saveOrUpdateAll(lastKnownRecords.values());
    _template.flush();
    _template.clear();
  }
 private void discardRecord(CcAndInferredLocationRecord record) {
   _log.error(
       "Discarding inferred record for vehicle : {} as inferred latitude or inferred longitude "
           + "values are out of range, or tripID/blockID is too long",
       record.getVehicleId());
 }