Skip to content

feat: add progress bar to elevation download #104

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: ors_4.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
-->
<maven.build.timestamp.format>yyyy-MM-dd'T'HH:mm:ss'Z'</maven.build.timestamp.format>
<builddate>${maven.build.timestamp}</builddate>
<log4j.version>2.22.1</log4j.version>
</properties>
<licenses>
<license>
Expand Down Expand Up @@ -136,6 +137,45 @@
<scope>test</scope>
<version>4.13.2</version>
</dependency>
<dependency>
<groupId>me.tongfei</groupId>
<artifactId>progressbar</artifactId>
<version>0.10.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j</artifactId>
<type>pom</type>
<version>${log4j.version}</version>
</dependency>

<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-1.2-api</artifactId>
<version>${log4j.version}</version>
</dependency>

<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${log4j.version}</version>
</dependency>

<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.core5</groupId>
<artifactId>httpcore5</artifactId>
<version>5.3.1</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.4.1</version>
</dependency>

</dependencies>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import com.graphhopper.storage.DataAccess;
import com.graphhopper.util.BitUtil;
import com.graphhopper.util.Downloader;
import com.graphhopper.util.ProgressBarLogger;
import com.graphhopper.util.ProgressListener;

import java.io.File;
import java.io.FileNotFoundException;
Expand Down Expand Up @@ -49,7 +51,11 @@ public abstract class AbstractSRTMElevationProvider extends TileBasedElevationPr
public AbstractSRTMElevationProvider(String baseUrl, String cacheDir, String downloaderName, int minLat, int maxLat, int defaultWidth) {
super(cacheDir);
this.baseUrl = baseUrl;
downloader = new Downloader(downloaderName).setTimeout(10000);

ProgressBarLogger.setLoggerName(AbstractTiffElevationProvider.class.getName());
ProgressListener progressListener = ProgressBarLogger.getProgressListener("Download elevation data");

this.downloader = new Downloader(downloaderName, progressListener).setTimeout(10000);
this.DEFAULT_WIDTH = defaultWidth;
this.MIN_LAT = minLat;
this.MAX_LAT = maxLat;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

import com.graphhopper.storage.DataAccess;
import com.graphhopper.util.Downloader;
import com.graphhopper.util.ProgressBarLogger;
import com.graphhopper.util.ProgressListener;

import java.awt.image.Raster;
import java.io.File;
Expand Down Expand Up @@ -47,7 +49,11 @@ public abstract class AbstractTiffElevationProvider extends TileBasedElevationPr
public AbstractTiffElevationProvider(String baseUrl, String cacheDir, String downloaderName, int width, int height, int latDegree, int lonDegree) {
super(cacheDir);
this.baseUrl = baseUrl;
this.downloader = new Downloader(downloaderName).setTimeout(10000);

ProgressBarLogger.setLoggerName(AbstractTiffElevationProvider.class.getName());
ProgressListener progressListener = ProgressBarLogger.getProgressListener("Download elevation data");

this.downloader = new Downloader(downloaderName, progressListener).setTimeout(10000);
this.WIDTH = width;
this.HEIGHT = height;
this.LAT_DEGREE = latDegree;
Expand Down
82 changes: 67 additions & 15 deletions core/src/main/java/com/graphhopper/util/Downloader.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@
import java.util.zip.GZIPInputStream;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.http.HttpEntity;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.Header;

/**
* @author Peter Karich
Expand All @@ -32,9 +39,15 @@ public class Downloader {
private String referrer = "http://graphhopper.com";
private String acceptEncoding = "gzip, deflate";
private int timeout = 4000;
private final ProgressListener progressListener;

public Downloader(String userAgent) {
public Downloader(String userAgent, ProgressListener progressListener) {
this.userAgent = userAgent;
this.progressListener = progressListener;
}

public Downloader(String userAgent) {
this(userAgent, null);
}

public static void main(String[] args) throws IOException {
Expand Down Expand Up @@ -110,21 +123,60 @@ public HttpURLConnection createConnection(String urlStr) throws IOException {
}

public void downloadFile(String url, String toFile) throws IOException {
HttpURLConnection conn = createConnection(url);
InputStream iStream = fetch(conn, false);
int size = 8 * 1024;
BufferedOutputStream writer = new BufferedOutputStream(new FileOutputStream(toFile), size);
InputStream in = new BufferedInputStream(iStream, size);
try {
byte[] buffer = new byte[size];
int numRead;
while ((numRead = in.read(buffer)) != -1) {
writer.write(buffer, 0, numRead);
final int bufferSize = 4096; // 4kB buffer
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
HttpGet httpGet = new HttpGet(url);

try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
int statusCode = response.getCode();
if (statusCode < 200 || statusCode >= 300) {
throw new IOException("Server returned HTTP response code: " + statusCode + " for URL: " + url);
}

HttpEntity entity = response.getEntity();
if (entity == null) {
throw new IOException("No entity found in response for URL: " + url);
}

long contentLength = entity.getContentLength(); // Länge von der Entity holen
if (contentLength <= 0) {
Header lengthHeader = response.getFirstHeader("Content-Length");
if(lengthHeader != null) {
try {
contentLength = Long.parseLong(lengthHeader.getValue());
} catch (NumberFormatException e) {
contentLength = -1;
}
}
}

try (InputStream inputStream = entity.getContent(); // InputStream ist AutoCloseable
BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(toFile))) {

byte[] buffer = new byte[bufferSize];
int numRead;
long totalBytesRead = 0;
int lastPercentage = -1;

while ((numRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, numRead);
totalBytesRead += numRead;

if (progressListener != null && contentLength > 0) {
int currentPercentage = (int) (100 * totalBytesRead / (double) contentLength);
if (currentPercentage > lastPercentage) {
progressListener.update(currentPercentage);
lastPercentage = currentPercentage;
}
}
}
if (progressListener != null && contentLength > 0 && lastPercentage < 100) {
progressListener.update(100);
}
} finally {
EntityUtils.consume(entity);
}
}
} finally {
Helper.close(iStream);
Helper.close(writer);
Helper.close(in);
}
}

Expand Down
126 changes: 126 additions & 0 deletions core/src/main/java/com/graphhopper/util/ProgressBarLogger.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package com.graphhopper.util;

import me.tongfei.progressbar.DelegatingProgressBarConsumer;
import me.tongfei.progressbar.ProgressBar;
import me.tongfei.progressbar.ProgressBarBuilder;
import me.tongfei.progressbar.ProgressBarStyle;
import org.apache.log4j.Logger;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.ConsoleAppender;
import org.apache.logging.log4j.core.config.AppenderRef;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.layout.PatternLayout;


public class ProgressBarLogger {
private static String LOGGER_NAME = "ProgressBarLogger";
private static final Logger CLASS_LOGGER = Logger.getLogger(ProgressBarLogger.class);


private static Logger initializeLogger() {
LoggerContext context = LoggerContext.getContext(false);
Configuration config = context.getConfiguration();
if (Logger.getRootLogger().getAppender(LOGGER_NAME) == null) {
String originalConsolePattern;
try {
originalConsolePattern = config.getAppender("Console").getLayout().getContentFormat().get("format");
} catch (Exception e) {
originalConsolePattern = "%d{yyyy-MM-dd HH:mm:ss} %highlight{%-7p} %style{%50t}{Cyan} %style{[ %-40.40c{1.} ]}{Bright Cyan} %m";
}

// Remove new line characters from the end of the pattern
if (originalConsolePattern.endsWith("%n")) {
originalConsolePattern = originalConsolePattern.substring(0, originalConsolePattern.length() - 2);
}

// Remove new line characters from the beginning of the pattern
if (originalConsolePattern.startsWith("%n")) {
originalConsolePattern = originalConsolePattern.substring(2);
}

final PatternLayout layout = PatternLayout.newBuilder()
.withPattern(originalConsolePattern + "\r")
.withConfiguration(config)
.build();

Appender consoleAppender = ConsoleAppender.newBuilder()
.setConfiguration(config)
.setName(LOGGER_NAME)
.setLayout(layout)
.setFilter(null)
.setTarget(ConsoleAppender.Target.SYSTEM_OUT)
.setName(LOGGER_NAME)
.setFollow(false)
.build();
consoleAppender.start();

// Create the new appender reference
AppenderRef ref = AppenderRef.createAppenderRef(LOGGER_NAME, null, null);
AppenderRef[] refs = new AppenderRef[]{ref};
LoggerConfig loggerConfig = LoggerConfig.newBuilder()
.withAdditivity(false)
.withLevel(Level.INFO)
.withLoggerName(LOGGER_NAME)
.withIncludeLocation("true")
.withRefs(refs)
.withProperties(null)
.withConfig(config)
.withtFilter(null)
.build();

config.addAppender(consoleAppender);
loggerConfig.addAppender(consoleAppender, null, null);
config.addLogger(LOGGER_NAME, loggerConfig);
context.updateLoggers();
}
return Logger.getLogger(LOGGER_NAME);
}

public static void setLoggerName(String loggerName) {
LOGGER_NAME = loggerName;
}

public static String getLoggerName() {
return LOGGER_NAME;
}

public static Logger getLogger() {
return initializeLogger();
}

/**
* Creates and returns a ProgressListener that receives percentages and updates a progress bar with the given task name.
*
* @param taskName the name of the task to be displayed in the progress bar
* @return a ProgressListener that updates the progress bar
*/
public static ProgressListener getProgressListener(String taskName) {
Logger logger = initializeLogger();
return new ProgressListener() {
final ProgressBarBuilder progressBarBuilder = new ProgressBarBuilder()
.setStyle(ProgressBarStyle.COLORFUL_UNICODE_BAR)
.setUpdateIntervalMillis(1000) // slow update for better visualization and less IO. Avoids % calculation for each element.
.setInitialMax(100)
.setTaskName(taskName)
.setConsumer(new DelegatingProgressBarConsumer(logger::info));

ProgressBar progressBar;

int lastPercentage = 0;
@Override
public void update(long val) {
if (progressBar == null) {
progressBar = progressBarBuilder.build();
}

if (val > lastPercentage) {
progressBar.stepTo(val);
lastPercentage = (int) val;
}
}
};
}
}