All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opentripplanner.routing.impl.GraphScanner Maven / Gradle / Ivy

package org.opentripplanner.routing.impl;

import java.io.File;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import org.opentripplanner.routing.error.GraphNotFoundException;
import org.opentripplanner.routing.services.GraphService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Scan for graphs under the base directory and auto-register them.
 */
public class GraphScanner {

    private static final Logger LOG = LoggerFactory.getLogger(GraphScanner.class);

    /** Auto-scan for new graphs every n secs. */
    private static final int AUTOSCAN_PERIOD_SEC = 10;

    /** Where to look for graphs. Defaults to 'graphs' under the OTP server base path. */
    public File basePath = null;

    /** A list of routerIds to automatically register and load at startup */
    public List autoRegister;

    /** The default router, none by default */
    public String defaultRouterId = null;

    /** The GraphService where register graphs to */
    private GraphService graphService;

    private ScheduledExecutorService scanExecutor;

    public GraphScanner(GraphService graphService, File basePath, boolean autoScan) {
        this.graphService = graphService;
        this.basePath = basePath;
        if (autoScan) {
            scanExecutor = Executors.newSingleThreadScheduledExecutor();
        }
    }

    /**
     * Based on the autoRegister list, automatically register all routerIds for which we can find a
     * graph file in a subdirectory of the resourceBase path. Also register and load the graph for
     * the defaultRouterId and warn if no routerIds are registered.
     */
    public void startup() {
        Set routerIds = new HashSet();
        if (autoRegister != null)
            routerIds.addAll(autoRegister);
        if (defaultRouterId != null) {
            graphService.setDefaultRouterId(defaultRouterId);
            routerIds.add(defaultRouterId);
        }
        if (!routerIds.isEmpty()) {
            LOG.info("Attempting to automatically register routerIds {}", autoRegister);
            LOG.info("Graph files will be sought in paths relative to {}", basePath);
            for (String routerId : routerIds) {
                InputStreamGraphSource graphSource = InputStreamGraphSource.newFileGraphSource(
                        routerId, getBasePath(routerId));
                graphService.registerGraph(routerId, graphSource);
            }
        } else {
            LOG.info("No list of routerIds was provided for automatic registration.");
        }
        if (scanExecutor != null) {
            LOG.info("Auto-scan mode activated, looking in {}", basePath);
            autoScan();
            scanExecutor.scheduleWithFixedDelay(new Runnable() {
                @Override
                public void run() {
                    autoScan();
                }
            }, AUTOSCAN_PERIOD_SEC, AUTOSCAN_PERIOD_SEC, TimeUnit.SECONDS);
        }
    }

    private void autoScan() {
        LOG.debug("Auto discovering graphs under {}", basePath);
        /*
         * There is no need to synchronize scan and registration here. If a graph file is removed
         * between scan and register, registering will fail but it's safe. It a graph file is
         * created, we'll wait for the next scan to register it.
         */
        Set graphOnDisk = new HashSet();
        /* First check for a root graph */
        File rootGraphFile = new File(basePath, InputStreamGraphSource.GRAPH_FILENAME);
        if (rootGraphFile.exists() && rootGraphFile.canRead()) {
            graphOnDisk.add("");
        }
        /* Then graph in sub-directories */
        for (String sub : basePath.list()) {
            File subPath = new File(basePath, sub);
            if (subPath.isDirectory()) {
                File graphFile = new File(subPath, InputStreamGraphSource.GRAPH_FILENAME);
                if (graphFile.exists() && graphFile.canRead()) {
                    graphOnDisk.add(sub);
                }
            }
        }
        Set graphRegistered = new HashSet<>(graphService.getRouterIds());
        Set graphToRegister = new HashSet<>(graphOnDisk);
        graphToRegister.removeAll(graphRegistered);

        if (!graphToRegister.isEmpty()) {
            LOG.info("Found new routers to register: {}",
                    Arrays.toString(graphToRegister.toArray()));
            for (String routerId : graphToRegister) {
                InputStreamGraphSource graphSource = InputStreamGraphSource.newFileGraphSource(
                        routerId, getBasePath(routerId));
                // Can be null here if the file has been removed in the meantime.
                graphService.registerGraph(routerId, graphSource);
            }
        }
        /*
         * Note: We do not automatically evict removed graph. They will be evicted only in
         * auto-reload mode, and that's the behavior we want.
         */
        Collection routerIds = graphService.getRouterIds();
        if (routerIds.isEmpty()) {
            LOG.warn("No graphs have been loaded/registered. "
                    + "You must place one or more graphs before routing.");
        } else {
            try {
                // Check if we still have a default graph.
                graphService.getRouter();
            } catch (GraphNotFoundException e) {
                // Let's see which one we want to take by default
                if (routerIds.contains("")) {
                    // If we have a root graph, this should be a good default
                    LOG.info("Setting default routerId to root graph ''");
                    graphService.setDefaultRouterId("");
                } else {
                    // Otherwise take first one present
                    String defRouterId = routerIds.iterator().next();
                    if (routerIds.size() > 1)
                        LOG.warn("Setting default routerId to arbitrary one '{}'", defRouterId);
                    else
                        LOG.info("Setting default routerId to '{}'", defRouterId);
                    graphService.setDefaultRouterId(defRouterId);
                }
            }
        }
    }

    private File getBasePath(String routerId) {
        return new File(basePath, routerId);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy