com.kurtraschke.wmata.gtfsrealtime.services.WMATARouteMapperService.java Source code

Java tutorial

Introduction

Here is the source code for com.kurtraschke.wmata.gtfsrealtime.services.WMATARouteMapperService.java

Source

/*
 * Copyright (C) 2014 Kurt Raschke <kurt@kurtraschke.com>
 *
 * 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 com.kurtraschke.wmata.gtfsrealtime.services;

import org.onebusaway.gtfs.model.AgencyAndId;
import org.onebusaway.gtfs.model.Route;
import org.onebusaway.gtfs.services.GtfsRelationalDao;

import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.kurtraschke.wmata.gtfsrealtime.WMATAAPIException;
import com.kurtraschke.wmata.gtfsrealtime.api.routes.WMATARoute;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;

/**
 *
 * @author kurt
 */
@Singleton
public class WMATARouteMapperService {

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

    private WMATAAPIService _api;
    private GtfsRelationalDao _dao;
    private String[] _badRoutes;
    private String _agencyId;
    private Properties _staticMappings;

    private final Pattern _routeExtract = Pattern.compile("^([A-Z0-9]+)(c?v?S?[0-9]?).*$");
    private Map<String, AgencyAndId> _routeMappings = new HashMap<String, AgencyAndId>();
    private Predicate<String> _matchBadRoutes;
    private List<Route> _gtfsRoutes;

    @Inject
    public void setWMATAAPIService(WMATAAPIService api) {
        _api = api;
    }

    @Inject
    public void setGtfsRelationalDao(GtfsRelationalDao dao) {
        _dao = dao;
    }

    @Inject
    public void setBadRoutes(@Named("WMATA.badRoutes") String badRoutesString) {
        _badRoutes = badRoutesString.split(",");
        _matchBadRoutes = Predicates.in(Arrays.asList(_badRoutes));
    }

    @Inject
    public void setAgencyId(@Named("WMATA.agencyID") String agencyId) {
        _agencyId = agencyId;
    }

    @Inject
    public void setStaticMappings(@Named("WMATA.staticMappings") Properties staticMappings) {
        _staticMappings = staticMappings;
    }

    @PostConstruct
    public void start() throws WMATAAPIException {
        _gtfsRoutes = _dao.getRoutesForAgency(_dao.getAgencyForId(_agencyId));
        primeCaches();
    }

    public void primeCaches() throws WMATAAPIException {
        for (WMATARoute r : _api.downloadRouteList().getRoutes()) {
            AgencyAndId mapResult = mapBusRoute(r.getRouteID());

            if (mapResult != null) {
                _routeMappings.put(r.getRouteID(), mapResult);
            }
        }

        String[] railRoutes = new String[] { "RED", "ORANGE", "YELLOW", "GREEN", "BLUE", "SILVER" }; //FIXME: avoid hardcoding

        for (String r : railRoutes) {
            AgencyAndId mapResult = mapRailRoute(r);

            if (mapResult != null) {
                _routeMappings.put(r, mapResult);
            }
        }
    }

    private AgencyAndId mapBusRoute(String routeID) {
        if (_staticMappings.containsKey(routeID)) {
            String staticMappedRoute = _staticMappings.getProperty(routeID);
            Optional<Route> matchedRoute = Iterables.tryFind(_gtfsRoutes,
                    new ShortNameFilterPredicate(staticMappedRoute, true));

            if (matchedRoute.isPresent()) {
                AgencyAndId mappedRouteID = matchedRoute.get().getId();
                _log.info(
                        "Mapped WMATA route " + routeID + " to GTFS route " + mappedRouteID + " (using override)");
                return mappedRouteID;
            } else {
                _log.warn("Could not apply static mapping of {} to {}; continuing...", routeID, staticMappedRoute);
            }
        }

        Matcher m = _routeExtract.matcher(routeID);

        if (m.matches()) {
            final String filteredRouteID = m.group(1);
            if (!_matchBadRoutes.apply(filteredRouteID)) {
                Optional<Route> matchedRoute = Iterables.tryFind(_gtfsRoutes,
                        new ShortNameFilterPredicate(filteredRouteID, true));

                if (matchedRoute.isPresent()) {
                    AgencyAndId mappedRouteID = matchedRoute.get().getId();
                    _log.info("Mapped WMATA route " + routeID + " to GTFS route " + mappedRouteID);
                    return mappedRouteID;
                } else {
                    _log.warn("Could not map WMATA route: " + routeID);
                    return null;
                }
            } else {
                _log.warn("Not mapping blacklisted WMATA route: " + routeID);
                return null;
            }
        } else {
            _log.warn("Not mapping malformed WMATA route: " + routeID);
            return null;
        }
    }

    private AgencyAndId mapRailRoute(String routeName) {
        Optional<Route> matchedRoute = Iterables.tryFind(_gtfsRoutes,
                new ShortNameFilterPredicate(routeName, false));

        if (matchedRoute.isPresent()) {
            AgencyAndId mappedRouteID = matchedRoute.get().getId();
            _log.info("Mapped WMATA route " + routeName + " to GTFS route " + mappedRouteID);
            return mappedRouteID;
        } else {
            _log.warn("Could not map WMATA route: " + routeName);
            return null;
        }
    }

    public AgencyAndId getRouteMapping(String routeID) {
        if (_routeMappings.containsKey(routeID)) {
            return _routeMappings.get(routeID);
        } else {
            return null;
        }
    }

    public Map<String, AgencyAndId> getRouteMappings() {
        return ImmutableMap.<String, AgencyAndId>copyOf(_routeMappings);
    }

    private static class ShortNameFilterPredicate implements Predicate<Route> {

        private String shortName;
        private boolean caseSensitive;

        public ShortNameFilterPredicate(String shortName, boolean caseSensitive) {
            this.shortName = shortName;
            this.caseSensitive = caseSensitive;
        }

        @Override
        public boolean apply(Route r) {
            if (r.getShortName() != null) {
                if (caseSensitive) {
                    return r.getShortName().equals(shortName);
                } else {
                    return r.getShortName().equalsIgnoreCase(shortName);
                }
            } else {
                return false;
            }
        }
    }
}