package org.opentripplanner.standalone; import java.io.File; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import lombok.Setter; import org.opentripplanner.analyst.core.GeometryIndex; import org.opentripplanner.analyst.request.Renderer; import org.opentripplanner.analyst.request.SPTCache; import org.opentripplanner.analyst.request.SampleFactory; import org.opentripplanner.analyst.request.TileCache; import org.opentripplanner.api.ws.PlanGenerator; import org.opentripplanner.api.ws.services.MetadataService; import org.opentripplanner.graph_builder.GraphBuilderTask; import org.opentripplanner.graph_builder.impl.GtfsGraphBuilderImpl; import org.opentripplanner.graph_builder.impl.StreetlessStopLinker; import org.opentripplanner.graph_builder.impl.TransitToStreetNetworkGraphBuilderImpl; import org.opentripplanner.graph_builder.impl.ned.NEDGraphBuilderImpl; import org.opentripplanner.graph_builder.impl.ned.NEDGridCoverageFactoryImpl; import org.opentripplanner.graph_builder.impl.osm.OpenStreetMapGraphBuilderImpl; import org.opentripplanner.graph_builder.model.GtfsBundle; import org.opentripplanner.graph_builder.services.GraphBuilder; import org.opentripplanner.graph_builder.services.ned.NEDGridCoverageFactory; import org.opentripplanner.openstreetmap.impl.AnyFileBasedOpenStreetMapProviderImpl; import org.opentripplanner.openstreetmap.services.OpenStreetMapProvider; import org.opentripplanner.routing.algorithm.GenericAStar; import org.opentripplanner.routing.core.RoutingRequest; import org.opentripplanner.routing.graph.Graph; import org.opentripplanner.routing.impl.DefaultRemainingWeightHeuristicFactoryImpl; import org.opentripplanner.routing.impl.GraphServiceBeanImpl; import org.opentripplanner.routing.impl.GraphServiceImpl; import org.opentripplanner.routing.impl.RetryingPathServiceImpl; import org.opentripplanner.routing.services.GraphService; import org.opentripplanner.routing.services.PathService; import org.opentripplanner.routing.services.RemainingWeightHeuristicFactory; import org.opentripplanner.routing.services.SPTService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.Lists; public class OTPConfigurator { private static final Logger LOG = LoggerFactory.getLogger(OTPConfigurator.class); private final CommandLineParameters params; /* If non-null, the in-memory graph to use (rather than loading from disk) */ @Setter private Graph graph; public OTPConfigurator (CommandLineParameters params) { this.params = params; } /** * Create an adapter to make Jersey see OTP as a dependency injection framework. * This will associate our specific OTP component instances with their interface classes. */ public OTPComponentProviderFactory providerFromParameters() { LOG.info("Wiring up and configuring server task."); // The PathService which wraps the SPTService RetryingPathServiceImpl pathService = new RetryingPathServiceImpl(); pathService.setFirstPathTimeout(10.0); pathService.setMultiPathTimeout(1.0); // Core OTP modules OTPComponentProviderFactory cpf = new OTPComponentProviderFactory(); cpf.bind(GraphService.class, makeGraphService()); cpf.bind(RoutingRequest.class); cpf.bind(PlanGenerator.class); cpf.bind(MetadataService.class); cpf.bind(SPTService.class, new GenericAStar()); cpf.bind(PathService.class, pathService); cpf.bind(RemainingWeightHeuristicFactory.class, new DefaultRemainingWeightHeuristicFactoryImpl()); // Optional Analyst Modules if (params.analyst) { cpf.bind(Renderer.class); cpf.bind(SPTCache.class); cpf.bind(TileCache.class); cpf.bind(GeometryIndex.class); cpf.bind(SampleFactory.class); } // Perform field injection on bound instances and call post-construct methods cpf.doneBinding(); return cpf; } private GraphService makeGraphService() { /* Hand off graph in memory to server in a single-graph in-memory GraphServiceImpl. */ if (graph != null && params.inMemory) { return new GraphServiceBeanImpl(graph); } /* Create a conventional GraphService that loads graphs from disk. */ GraphServiceImpl graphService = new GraphServiceImpl(); if (params.graphDirectory != null) { graphService.setPath(params.graphDirectory); } if (params.defaultRouterId != null) { graphService.setDefaultRouterId(params.defaultRouterId); } return graphService; } public GraphBuilderTask builderFromParameters() { LOG.info("Wiring up and configuring graph builder task."); if (params.build == null || params.build.isEmpty()) { return null; } GraphBuilderTask graphBuilder = new GraphBuilderTask(); List<File> gtfsFiles = Lists.newArrayList(); List<File> osmFiles = Lists.newArrayList(); /* For now this is adding files from all directories listed, rather than building multiple graphs. */ for (File dir : params.build) { LOG.info("Searching for graph builder input files in {}", dir); if ( ! dir.isDirectory() && dir.canRead()) { LOG.error("'{}' is not a readable directory.", dir); continue; } graphBuilder.setPath(dir); for (File file : dir.listFiles()) { switch (InputFileType.forFile(file)) { case GTFS: LOG.info("Found GTFS file {}", file); gtfsFiles.add(file); break; case OSM: LOG.info("Found OSM file {}", file); osmFiles.add(file); break; case OTHER: LOG.debug("Skipping file '{}'", file); } } } boolean hasOSM = ! (osmFiles.isEmpty() || params.noStreets); boolean hasGTFS = ! (gtfsFiles.isEmpty() || params.noTransit); if ( ! (hasOSM || hasGTFS )) { LOG.error("Found no input files from which to build a graph in {}", params.build.toString()); return null; } if ( hasOSM ) { List<OpenStreetMapProvider> osmProviders = Lists.newArrayList(); for (File osmFile : osmFiles) { OpenStreetMapProvider osmProvider = new AnyFileBasedOpenStreetMapProviderImpl(osmFile); osmProviders.add(osmProvider); } GraphBuilder osmBuilder = new OpenStreetMapGraphBuilderImpl(osmProviders); graphBuilder.addGraphBuilder(osmBuilder); } if ( hasGTFS ) { List<GtfsBundle> gtfsBundles = Lists.newArrayList(); for (File gtfsFile : gtfsFiles) { GtfsBundle gtfsBundle = new GtfsBundle(gtfsFile); gtfsBundle.setTransfersTxtDefinesStationPaths(params.useTransfersTxt); gtfsBundles.add(gtfsBundle); } GraphBuilder gtfsBuilder = new GtfsGraphBuilderImpl(gtfsBundles); graphBuilder.addGraphBuilder(gtfsBuilder); if ( hasOSM ) { graphBuilder.addGraphBuilder(new TransitToStreetNetworkGraphBuilderImpl()); } else { graphBuilder.addGraphBuilder(new StreetlessStopLinker()); } } if (params.elevation) { File cacheDirectory = new File(params.cacheDirectory, "ned"); NEDGridCoverageFactory ngcf = new NEDGridCoverageFactoryImpl(cacheDirectory); GraphBuilder nedBuilder = new NEDGraphBuilderImpl(ngcf); graphBuilder.addGraphBuilder(nedBuilder); } graphBuilder.setSerializeGraph( ! params.inMemory); return graphBuilder; } public GrizzlyServer serverFromParameters() { OTPComponentProviderFactory cpf = providerFromParameters(); GrizzlyServer server = new GrizzlyServer(cpf, params); return server; } private static enum InputFileType { GTFS, OSM, OTHER; public static InputFileType forFile(File file) { String name = file.getName(); if (name.endsWith(".zip")) { try { ZipFile zip = new ZipFile(file); ZipEntry stopTimesEntry = zip.getEntry("stop_times.txt"); zip.close(); if (stopTimesEntry != null) return GTFS; } catch (Exception e) { /* fall through */ } } if (name.endsWith(".pbf")) return OSM; if (name.endsWith(".osm")) return OSM; if (name.endsWith(".osm.xml")) return OSM; return OTHER; } } }