Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package org.opentripplanner.routing.services;
import org.geotools.referencing.factory.DeferredAuthorityFactory;
import org.geotools.util.WeakCollectionCleaner;
import org.opentripplanner.routing.error.GraphNotFoundException;
import org.opentripplanner.standalone.Router;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.PreDestroy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* A GraphService maps RouterIds to Graphs.
*
* This graph service allows us to decouple the deserialization, loading, and management of the
* underlying graph objects from the classes that need access to the objects. This indirection
* allows us to provide multiple graphs distringuished by routerIds or to dynamically swap in new
* graphs if underlying data changes.
*
* Delegate the graph creation/loading details to the GraphSource implementations.
*
* @see GraphSource
*/
public class GraphService {
private static final Logger LOG = LoggerFactory.getLogger(GraphService.class);
/** Poll period for auto-reload scan. */
private static final int AUTORELOAD_PERIOD_SEC = 10;
/**
* Should we pre-evict in auto-reload mode? False is more memory consuming but safer in case of
* problems.
*/
private static final boolean AUTORELOAD_PREEVICT = false;
private Map graphSources = new HashMap<>();
private static final Pattern routerIdPattern = Pattern.compile("[\\p{Alnum}_-]*");
private String defaultRouterId = "";
public GraphSource.Factory graphSourceFactory;
private ScheduledExecutorService scanExecutor;
public GraphService() {
this(false);
}
public GraphService(boolean autoReload) {
if (autoReload) {
scanExecutor = Executors.newSingleThreadScheduledExecutor();
scanExecutor.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
autoReloadScan();
}
}, AUTORELOAD_PERIOD_SEC, AUTORELOAD_PERIOD_SEC, TimeUnit.SECONDS);
}
}
/** @param defaultRouterId The ID of the default router to return when no one is specified */
public void setDefaultRouterId(String defaultRouterId) {
this.defaultRouterId = defaultRouterId;
}
/**
* This is called when the bean gets deleted, that is mainly in case of webapp container
* application stop or reload. We teardown all loaded graph to stop their background real-time
* data updater thread.
*/
@PreDestroy
private void teardown() {
LOG.info("Cleaning-up graphs...");
evictAll();
cleanupWebapp();
}
/**
* @return the current default router object
*/
public Router getRouter() throws GraphNotFoundException {
return getRouter(null);
}
/**
* @return the graph object for the given router ID
*/
public Router getRouter(String routerId) throws GraphNotFoundException {
if (routerId == null || routerId.isEmpty() || routerId.equalsIgnoreCase("default")) {
routerId = defaultRouterId;
LOG.debug("routerId not specified, set to default of '{}'", routerId);
}
/*
* Here we should not synchronize on graphSource as it may block for a while (during
* reload/autoreload). For normal operations a simple get do not need to be synchronized so
* we should be safe.
*/
GraphSource graphSource = graphSources.get(routerId);
if (graphSource == null) {
LOG.error("no graph registered with the routerId '{}'", routerId);
throw new GraphNotFoundException();
}
Router router = graphSource.getRouter();
if (router == null) {
evictRouter(routerId);
throw new GraphNotFoundException();
}
return router;
}
/**
* Reload all registered graphs from wherever they came from. See reloadGraph().
* @return whether the operation completed successfully (all reloads are successful).
*/
public boolean reloadGraphs(boolean preEvict, boolean force) {
boolean allSucceeded = true;
synchronized (graphSources) {
Collection routerIds = getRouterIds();
for (String routerId : routerIds) {
allSucceeded &= reloadGraph(routerId, preEvict, force);
}
}
return allSucceeded;
}
/**
* Reload a registered graph. If the reload fails, evict (remove) the graph.
*
* @param routerId ID of the router
* @param preEvict When true, release the existing graph (if any) before loading. This will
* halve the amount of memory needed for the operation, but routing will be unavailable
* for that graph during the load process
* @param force When true, force a reload. If false, only check if the source has been modified,
* and reload if so.
* @return True if the reload is successful, false otherwise.
*/
public boolean reloadGraph(String routerId, boolean preEvict, boolean force) {
synchronized (graphSources) {
GraphSource graphSource = graphSources.get(routerId);
if (graphSource == null) {
return false;
}
boolean success = graphSource.reload(force, preEvict);
if (!success) {
evictRouter(routerId);
}
return success;
}
}
/** @return a collection of all valid router IDs for this server */
public Collection getRouterIds() {
return new ArrayList(graphSources.keySet());
}
/**
* Blocking method to associate the specified router ID with the corresponding graph source,
* load it from appropriate source (serialized file, memory...), and enable its use in routing.
* The relationship between router IDs and paths in the filesystem is determined by the
* GraphSource implementation.
*
* @return whether the operation completed successfully
*/
public boolean registerGraph(String routerId, GraphSource graphSource) {
LOG.info("Registering new router '{}'", routerId);
if (!routerIdLegal(routerId)) {
LOG.error(
"routerId '{}' contains characters other than alphanumeric, underscore, and dash.",
routerId);
return false;
}
graphSource.reload(true, false);
if (graphSource.getRouter() == null) {
LOG.warn("Can't register router ID '{}', no graph.", routerId);
return false;
}
synchronized (graphSources) {
GraphSource oldSource = graphSources.get(routerId);
if (oldSource != null) {
LOG.info("Graph '{}' already registered. Nothing to do.", routerId);
return false;
}
graphSources.put(routerId, graphSource);
return true;
}
}
/**
* Dissociate a router ID from the corresponding graph/services object, and disable that router ID for
* use in routing.
*
* @return whether a router was associated with this router ID and was evicted.
*/
public boolean evictRouter(String routerId) {
LOG.info("Evicting router '{}'", routerId);
synchronized (graphSources) {
GraphSource graphSource = graphSources.get(routerId);
graphSources.remove(routerId);
if (graphSource != null) {
graphSource.evict();
return true;
} else {
return false;
}
}
}
/**
* Dissocate all graphs from their router IDs and release references to the graphs to allow
* garbage collection. Routing will not be possible until new graphs are registered.
*
* This is equivalent to calling evictGraph on every registered router ID.
*/
public int evictAll() {
LOG.info("Evincting all graphs.");
synchronized (graphSources) {
int n = 0;
Collection routerIds = new ArrayList(getRouterIds());
for (String routerId : routerIds) {
if (evictRouter(routerId)) {
n++;
}
}
return n;
}
}
/**
* @return The default GraphSource factory. Needed in case someone want to register or save a
* new router with a router ID only (namely, via the web-service API).
*/
public GraphSource.Factory getGraphSourceFactory() {
return graphSourceFactory;
}
/**
* Hook to cleanup various stuff of some used libraries (org.geotools), which depend on the
* external client to call them for cleaning-up.
*/
private void cleanupWebapp() {
LOG.info("Web application shutdown: cleaning various stuff");
WeakCollectionCleaner.DEFAULT.exit();
DeferredAuthorityFactory.exit();
}
/**
* Check whether a router ID is legal or not.
*
* Router IDs may contain alphanumeric characters, underscores, and dashes only. This prevents
* any confusion caused by the presence of special characters that might have a meaning for the
* filesystem.
*/
public static boolean routerIdLegal(String routerId) {
Matcher m = routerIdPattern.matcher(routerId);
return m.matches();
}
private void autoReloadScan() {
synchronized (graphSources) {
Collection routerIds = getRouterIds();
for (String routerId : routerIds) {
GraphSource graphSource = graphSources.get(routerId);
boolean success = graphSource.reload(false, AUTORELOAD_PREEVICT);
if (!success) {
evictRouter(routerId);
}
}
}
}
}