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

org.opentripplanner.openstreetmap.OpenStreetMapProvider Maven / Gradle / Ivy

There is a newer version: 2.6.0
Show newest version
package org.opentripplanner.openstreetmap;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.time.ZoneId;
import org.openstreetmap.osmosis.osmbinary.file.BlockInputStream;
import org.opentripplanner.datastore.api.DataSource;
import org.opentripplanner.datastore.api.FileType;
import org.opentripplanner.datastore.file.FileDataSource;
import org.opentripplanner.graph_builder.ConfiguredDataSource;
import org.opentripplanner.graph_builder.module.osm.OSMDatabase;
import org.opentripplanner.graph_builder.module.osm.WayPropertySet;
import org.opentripplanner.graph_builder.module.osm.parameters.OsmDefaultParameters;
import org.opentripplanner.graph_builder.module.osm.parameters.OsmExtractParameters;
import org.opentripplanner.graph_builder.module.osm.parameters.OsmExtractParametersBuilder;
import org.opentripplanner.graph_builder.module.osm.tagmapping.OsmTagMapper;
import org.opentripplanner.openstreetmap.model.OSMProvider;
import org.opentripplanner.util.lang.ToStringBuilder;
import org.opentripplanner.util.logging.ProgressTracker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Parser for the OpenStreetMap PBF format. Parses files in three passes: First the relations, then
 * the ways, then the nodes are also loaded.
 */
public class OpenStreetMapProvider implements OSMProvider {

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

  private final DataSource source;
  private final boolean cacheDataInMem;

  private final ZoneId zoneId;

  private boolean hasWarnedAboutMissingTimeZone = false;

  private final OsmTagMapper osmTagMapper;

  private final WayPropertySet wayPropertySet;
  private byte[] cachedBytes = null;

  /** For tests */
  public OpenStreetMapProvider(File file, boolean cacheDataInMem) {
    this(new FileDataSource(file, FileType.OSM), cacheDataInMem);
  }

  public OpenStreetMapProvider(FileDataSource fileDataSource, boolean cacheDataInMem) {
    this(
      new ConfiguredDataSource<>(
        fileDataSource,
        new OsmExtractParametersBuilder().withSource(fileDataSource.uri()).build()
      ),
      new OsmDefaultParameters(),
      cacheDataInMem
    );
  }

  public OpenStreetMapProvider(
    ConfiguredDataSource osmExtractConfigConfiguredDataSource,
    OsmDefaultParameters defaultParameters,
    boolean cacheDataInMem
  ) {
    this.source = osmExtractConfigConfiguredDataSource.dataSource();
    this.zoneId =
      osmExtractConfigConfiguredDataSource.config().timeZone().orElse(defaultParameters.timeZone);
    this.osmTagMapper =
      osmExtractConfigConfiguredDataSource
        .config()
        .osmTagMapper()
        .orElse(defaultParameters.osmOsmTagMapper);
    this.wayPropertySet = new WayPropertySet();
    osmTagMapper.populateProperties(wayPropertySet);
    this.cacheDataInMem = cacheDataInMem;
  }

  public void readOSM(OSMDatabase osmdb) {
    try {
      OpenStreetMapParser parser = new OpenStreetMapParser(osmdb, this);

      parsePhase(parser, OsmParserPhase.Relations);
      osmdb.doneFirstPhaseRelations();

      parsePhase(parser, OsmParserPhase.Ways);
      osmdb.doneSecondPhaseWays();

      parsePhase(parser, OsmParserPhase.Nodes);
      osmdb.doneThirdPhaseNodes();
    } catch (Exception ex) {
      throw new IllegalStateException("error loading OSM from path " + source.path(), ex);
    }
  }

  @Override
  public String toString() {
    return ToStringBuilder
      .of(OpenStreetMapProvider.class)
      .addObj("source", source)
      .addBool("cacheDataInMem", cacheDataInMem)
      .toString();
  }

  public void checkInputs() {
    if (!source.exists()) {
      throw new RuntimeException("Can't read OSM path: " + source.path());
    }
  }

  @SuppressWarnings("Convert2MethodRef")
  private static InputStream track(OsmParserPhase phase, long size, InputStream inputStream) {
    // Keep logging lambda, replacing it with a method-ref will cause the
    // logging to report incorrect class and line number
    return ProgressTracker.track("Parse OSM " + phase, 1000, size, inputStream, m -> LOG.info(m));
  }

  private void parsePhase(OpenStreetMapParser parser, OsmParserPhase phase) throws IOException {
    parser.setPhase(phase);
    BlockInputStream in = null;
    try {
      in = new BlockInputStream(createInputStream(phase), parser);
      in.process();
    } finally {
      // Close
      try {
        if (in != null) {
          in.close();
        }
      } catch (Exception e) {
        LOG.error(e.getMessage(), e);
      }
    }
  }

  private InputStream createInputStream(OsmParserPhase phase) {
    if (cacheDataInMem) {
      if (cachedBytes == null) {
        cachedBytes = source.asBytes();
      }
      return track(phase, cachedBytes.length, new ByteArrayInputStream(cachedBytes));
    }
    return track(phase, source.size(), source.asInputStream());
  }

  @Override
  public ZoneId getZoneId() {
    if (zoneId == null) {
      if (!hasWarnedAboutMissingTimeZone) {
        hasWarnedAboutMissingTimeZone = true;
        LOG.warn(
          "Missing time zone for OSM source {} - time-restricted entities will not be created, please configure it in the build-config.json",
          source.uri()
        );
      }
    }
    return zoneId;
  }

  @Override
  public OsmTagMapper getOsmTagMapper() {
    return osmTagMapper;
  }

  @Override
  public WayPropertySet getWayPropertySet() {
    return wayPropertySet;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy