001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.plugins.streetside.io.download;
003
004import java.awt.GraphicsEnvironment;
005import java.io.IOException;
006import java.net.HttpURLConnection;
007import java.net.URL;
008import java.net.URLConnection;
009import java.text.MessageFormat;
010import java.util.function.Function;
011
012import org.apache.log4j.Logger;
013import org.openstreetmap.josm.data.Bounds;
014import org.openstreetmap.josm.gui.Notification;
015import org.openstreetmap.josm.plugins.streetside.StreetsidePlugin;
016import org.openstreetmap.josm.plugins.streetside.utils.StreetsideProperties;
017import org.openstreetmap.josm.plugins.streetside.utils.StreetsideURL.APIv3;
018import org.openstreetmap.josm.tools.ImageProvider.ImageSizes;
019
020public abstract class BoundsDownloadRunnable implements Runnable {
021
022  final static Logger logger = Logger.getLogger(BoundsDownloadRunnable.class);
023
024  protected Bounds bounds;
025  protected abstract Function<Bounds, URL> getUrlGenerator();
026
027  public BoundsDownloadRunnable(final Bounds bounds) {
028    this.bounds = bounds;
029  }
030
031  @Override
032  public void run() {
033    URL nextURL = getUrlGenerator().apply(bounds);
034    if(StreetsideProperties.DEBUGING_ENABLED.get()) {
035      logger.debug(MessageFormat.format("nextURL: {0}", nextURL.toString()));
036    }
037    try {
038      while (nextURL != null) {
039        if (Thread.interrupted()) {
040          logger.error(getClass().getSimpleName() + " for " +  bounds.toString() + " interrupted!");
041          return;
042        }
043        final URLConnection con = nextURL.openConnection();
044        run(con);
045        nextURL = APIv3.parseNextFromLinkHeaderValue(con.getHeaderField("Link"));
046      }
047    } catch (IOException e) {
048      String message = "Could not read from URL " +  nextURL.toString() + "!";
049      logger.warn(message, e);
050      if (!GraphicsEnvironment.isHeadless()) {
051        new Notification(message)
052          .setIcon(StreetsidePlugin.LOGO.setSize(ImageSizes.LARGEICON).get())
053          .setDuration(Notification.TIME_LONG)
054          .show();
055      }
056      e.printStackTrace();
057    }
058  }
059
060  /**
061   * Logs information about the given connection via {@link logger#info(String)}.
062   * If it's a {@link HttpURLConnection}, the request method, the response code and the URL itself are logged.
063   * Otherwise only the URL is logged.
064   * @param con the {@link URLConnection} for which information is logged
065   * @param info an additional info text, which is appended to the output in braces
066   * @throws IOException if {@link HttpURLConnection#getResponseCode()} throws an {@link IOException}
067   */
068  public static void logConnectionInfo(final URLConnection con, final String info) throws IOException {
069    final StringBuilder message;
070    if (con instanceof HttpURLConnection) {
071      message = new StringBuilder(((HttpURLConnection) con).getRequestMethod())
072        .append(' ').append(con.getURL())
073        .append(" → ").append(((HttpURLConnection) con).getResponseCode());
074    } else {
075      message = new StringBuilder("Download from ").append(con.getURL());
076    }
077    if (info != null && info.length() >= 1) {
078      message.append(" (").append(info).append(')');
079    }
080    logger.info(message.toString());
081  }
082
083  public abstract void run(final URLConnection connection) throws IOException;
084}