diff --git a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/GetDataRunnable.java b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/GetDataRunnable.java index d9a7253..af3fb82 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/GetDataRunnable.java +++ b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/GetDataRunnable.java @@ -5,6 +5,7 @@ import static org.openstreetmap.josm.tools.I18n.tr; import java.io.IOException; import java.io.InputStream; +import java.net.SocketException; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; @@ -27,6 +28,7 @@ import org.openstreetmap.josm.data.osm.Tag; import org.openstreetmap.josm.data.osm.UploadPolicy; import org.openstreetmap.josm.gui.progress.NullProgressMonitor; import org.openstreetmap.josm.gui.progress.ProgressMonitor; +import org.openstreetmap.josm.gui.progress.ProgressMonitor.CancelListener; import org.openstreetmap.josm.io.IllegalDataException; import org.openstreetmap.josm.plugins.mapwithai.MapWithAIPlugin; import org.openstreetmap.josm.plugins.mapwithai.commands.MergeDuplicateWays; @@ -40,9 +42,10 @@ import org.openstreetmap.josm.tools.Pair; * * @author Taylor Smock */ -public class GetDataRunnable extends RecursiveTask { +public class GetDataRunnable extends RecursiveTask implements CancelListener { private static final long serialVersionUID = 258423685658089715L; private final transient List bbox; + private static HttpClient client; private final transient DataSet dataSet; private final transient ProgressMonitor monitor; @@ -72,38 +75,47 @@ public class GetDataRunnable extends RecursiveTask { this.bbox = new ArrayList<>(bbox); this.dataSet = dataSet; this.monitor = Optional.ofNullable(monitor).orElse(NullProgressMonitor.INSTANCE); + this.monitor.addCancelListener(this); } @Override public DataSet compute() { final List bboxes = MapWithAIDataUtils.reduceBBoxSize(bbox); - monitor.beginTask(tr("Downloading {0} data", MapWithAIPlugin.NAME), bboxes.size() - 1); - if (bboxes.size() == MAX_NUMBER_OF_BBOXES_TO_PROCESS) { - final DataSet temporaryDataSet = getDataReal(bboxes.get(0)); - synchronized (GetDataRunnable.class) { - dataSet.mergeFrom(temporaryDataSet); + monitor.beginTask(tr("Downloading {0} data ({1} total downloads)", MapWithAIPlugin.NAME, bboxes.size()), + bboxes.size() - 1); + if (!monitor.isCanceled()) { + if (bboxes.size() == MAX_NUMBER_OF_BBOXES_TO_PROCESS) { + final DataSet temporaryDataSet = getDataReal(bboxes.get(0), monitor); + synchronized (GetDataRunnable.class) { + dataSet.mergeFrom(temporaryDataSet); + } + } else { + final Collection tasks = bboxes.parallelStream() + .map(tBbox -> new GetDataRunnable(tBbox, dataSet, monitor.createSubTaskMonitor(0, true))) + .collect(Collectors.toList()); + tasks.forEach(GetDataRunnable::fork); + tasks.parallelStream().forEach(runnable -> { + runnable.join(); + monitor.worked(1); + }); + } + } + // This can technically be included in the above block, but it is here so that + // cancellation is a little faster + if (!monitor.isCanceled()) { + synchronized (LOCK) { + /* Microsoft buildings don't have a source, so we add one */ + MapWithAIDataUtils.addSourceTags(dataSet, "building", "microsoft"); + replaceTags(dataSet); + removeCommonTags(dataSet); + mergeNodes(dataSet); + cleanupDataSet(dataSet); + for (int i = 0; i < 5; i++) { + new MergeDuplicateWays(dataSet).executeCommand(); + } } - } else { - final Collection tasks = bboxes.parallelStream() - .map(tBbox -> new GetDataRunnable(tBbox, dataSet, monitor.createSubTaskMonitor(1, true))) - .collect(Collectors.toList()); - tasks.forEach(GetDataRunnable::fork); - tasks.forEach(GetDataRunnable::join); } monitor.finishTask(); - - synchronized (LOCK) { - /* Microsoft buildings don't have a source, so we add one */ - MapWithAIDataUtils.addSourceTags(dataSet, "building", "microsoft"); - replaceTags(dataSet); - removeCommonTags(dataSet); - mergeNodes(dataSet); - // filterDataSet(dataSet); - cleanupDataSet(dataSet); - for (int i = 0; i < 5; i++) { - new MergeDuplicateWays(dataSet).executeCommand(); - } - } return dataSet; } @@ -165,6 +177,7 @@ public class GetDataRunnable extends RecursiveTask { bbox.addPrimitive(n1, 0.001); final List nearbyNodes = dataSet.searchNodes(bbox).parallelStream() .filter(node -> !node.isDeleted() && !node.equals(n1) + && n1.getKeys().equals(node.getKeys()) && n1.getCoor().greatCircleDistance(node.getCoor()) < MapWithAIPreferenceHelper .getMaxNodeDistance()) .collect(Collectors.toList()); @@ -179,10 +192,11 @@ public class GetDataRunnable extends RecursiveTask { /** * Actually get the data * - * @param bbox The bbox to get the data from + * @param bbox The bbox to get the data from + * @param monitor Use to determine if the operation has been cancelled * @return A dataset with the data from the bbox */ - private static DataSet getDataReal(BBox bbox) { + private static DataSet getDataReal(BBox bbox, ProgressMonitor monitor) { InputStream inputStream = null; final DataSet dataSet = new DataSet(); String urlString = MapWithAIPreferenceHelper.getMapWithAIUrl(); @@ -195,7 +209,7 @@ public class GetDataRunnable extends RecursiveTask { try { final URL url = new URL(urlString.replace("{bbox}", bbox.toStringCSV(",")).replace("{crop_bbox}", DetectTaskingManagerUtils.getTaskingManagerBBox().toStringCSV(","))); - final HttpClient client = HttpClient.create(url); + client = HttpClient.create(url); final StringBuilder defaultUserAgent = new StringBuilder(); defaultUserAgent.append(client.getHeaders().get("User-Agent")); if (defaultUserAgent.toString().trim().length() == 0) { @@ -203,12 +217,18 @@ public class GetDataRunnable extends RecursiveTask { } defaultUserAgent.append(tr("/ {0} {1}", MapWithAIPlugin.NAME, MapWithAIPlugin.getVersionInfo())); client.setHeader("User-Agent", defaultUserAgent.toString()); - Logging.debug("{0}: Getting {1}", MapWithAIPlugin.NAME, client.getURL().toString()); - final Response response = client.connect(); - inputStream = response.getContent(); - final DataSet mergeData = OsmReaderCustom.parseDataSet(inputStream, null, true); - dataSet.mergeFrom(mergeData); - response.disconnect(); + if (!monitor.isCanceled()) { + Logging.debug("{0}: Getting {1}", MapWithAIPlugin.NAME, client.getURL().toString()); + final Response response = client.connect(); + inputStream = response.getContent(); + final DataSet mergeData = OsmReaderCustom.parseDataSet(inputStream, null, true); + dataSet.mergeFrom(mergeData); + response.disconnect(); + } + } catch (SocketException e) { + if (!monitor.isCanceled()) { + Logging.debug(e); + } } catch (UnsupportedOperationException | IllegalDataException | IOException e) { Logging.debug(e); } finally { @@ -223,4 +243,11 @@ public class GetDataRunnable extends RecursiveTask { } return dataSet; } + + @Override + public void operationCanceled() { + if (client != null) { + client.disconnect(); + } + } } diff --git a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/MapWithAIDataUtils.java b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/MapWithAIDataUtils.java index 7c764d8..0d06c5e 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/MapWithAIDataUtils.java +++ b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/MapWithAIDataUtils.java @@ -146,7 +146,6 @@ public final class MapWithAIDataUtils { final DataSet dataSet = new DataSet(); final List realBBoxes = bbox.stream().filter(BBox::isValid).distinct().collect(Collectors.toList()); final PleaseWaitProgressMonitor monitor = new PleaseWaitProgressMonitor(); - monitor.setCancelable(Boolean.FALSE); getForkJoinPool().invoke(new GetDataRunnable(realBBoxes, dataSet, monitor)); monitor.finishTask(); monitor.close();