source: josm/trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadReferrersTask.java @ 13486

Last change on this file since 13486 was 13486, checked in by Don-vip, 5 months ago

fix #8039, see #10456 - fix bugs with non-downloadable layers

  • Property svn:eol-style set to native
File size: 7.8 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.actions.downloadtasks;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5import static org.openstreetmap.josm.tools.I18n.trn;
6
7import java.io.IOException;
8import java.text.MessageFormat;
9import java.util.Collection;
10import java.util.HashMap;
11import java.util.HashSet;
12import java.util.Map;
13import java.util.Map.Entry;
14import java.util.Set;
15
16import javax.swing.JOptionPane;
17import javax.swing.SwingUtilities;
18
19import org.openstreetmap.josm.Main;
20import org.openstreetmap.josm.data.osm.DataSet;
21import org.openstreetmap.josm.data.osm.DataSetMerger;
22import org.openstreetmap.josm.data.osm.Node;
23import org.openstreetmap.josm.data.osm.OsmPrimitive;
24import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
25import org.openstreetmap.josm.data.osm.PrimitiveId;
26import org.openstreetmap.josm.data.osm.Way;
27import org.openstreetmap.josm.gui.MainApplication;
28import org.openstreetmap.josm.gui.MapFrame;
29import org.openstreetmap.josm.gui.PleaseWaitRunnable;
30import org.openstreetmap.josm.gui.layer.OsmDataLayer;
31import org.openstreetmap.josm.gui.progress.ProgressMonitor;
32import org.openstreetmap.josm.io.MultiFetchServerObjectReader;
33import org.openstreetmap.josm.io.OsmServerBackreferenceReader;
34import org.openstreetmap.josm.io.OsmServerReader;
35import org.openstreetmap.josm.io.OsmTransferException;
36import org.openstreetmap.josm.tools.CheckParameterUtil;
37import org.openstreetmap.josm.tools.ExceptionUtil;
38import org.xml.sax.SAXException;
39
40/**
41 * The asynchronous task for downloading referring primitives
42 * @since 2923
43 */
44public class DownloadReferrersTask extends PleaseWaitRunnable {
45    private boolean canceled;
46    private Exception lastException;
47    private OsmServerReader reader;
48    /** the target layer */
49    private final OsmDataLayer targetLayer;
50    /** the collection of child primitives */
51    private final Map<Long, OsmPrimitiveType> children;
52    /** the parents */
53    private final DataSet parents;
54
55    /**
56     * constructor
57     *
58     * @param targetLayer  the target layer for the downloaded primitives. Must not be null.
59     * @param children the collection of child primitives for which parents are to be downloaded
60     */
61    public DownloadReferrersTask(OsmDataLayer targetLayer, Collection<OsmPrimitive> children) {
62        super("Download referrers", false /* don't ignore exception*/);
63        CheckParameterUtil.ensureParameterNotNull(targetLayer, "targetLayer");
64        if (!targetLayer.isDownloadable()) {
65            throw new IllegalArgumentException("Non-downloadable layer: " + targetLayer);
66        }
67        canceled = false;
68        this.children = new HashMap<>();
69        if (children != null) {
70            for (OsmPrimitive p: children) {
71                if (!p.isNew()) {
72                    this.children.put(p.getId(), OsmPrimitiveType.from(p));
73                }
74            }
75        }
76        this.targetLayer = targetLayer;
77        parents = new DataSet();
78    }
79
80    /**
81     * constructor
82     *
83     * @param targetLayer the target layer. Must not be null.
84     * @param primitiveId a PrimitiveId object.
85     * @param progressMonitor ProgressMonitor to use or null to create a new one.
86     * @throws IllegalArgumentException if id &lt;= 0
87     * @throws IllegalArgumentException if targetLayer == null
88     */
89    public DownloadReferrersTask(OsmDataLayer targetLayer, PrimitiveId primitiveId,
90            ProgressMonitor progressMonitor) {
91        super("Download referrers", progressMonitor, false /* don't ignore exception*/);
92        CheckParameterUtil.ensureParameterNotNull(targetLayer, "targetLayer");
93        if (primitiveId.isNew())
94            throw new IllegalArgumentException(MessageFormat.format(
95                    "Cannot download referrers for new primitives (ID {0})", primitiveId.getUniqueId()));
96        canceled = false;
97        this.children = new HashMap<>();
98        this.children.put(primitiveId.getUniqueId(), primitiveId.getType());
99        this.targetLayer = targetLayer;
100        parents = new DataSet();
101    }
102
103    @Override
104    protected void cancel() {
105        canceled = true;
106        synchronized (this) {
107            if (reader != null) {
108                reader.cancel();
109            }
110        }
111    }
112
113    @Override
114    protected void finish() {
115        if (canceled)
116            return;
117        if (lastException != null) {
118            ExceptionUtil.explainException(lastException);
119            return;
120        }
121
122        DataSetMerger visitor = new DataSetMerger(targetLayer.data, parents);
123        visitor.merge();
124        SwingUtilities.invokeLater(targetLayer::onPostDownloadFromServer);
125        if (visitor.getConflicts().isEmpty())
126            return;
127        targetLayer.getConflicts().add(visitor.getConflicts());
128        JOptionPane.showMessageDialog(
129                Main.parent,
130                trn("There was {0} conflict during import.",
131                    "There were {0} conflicts during import.",
132                    visitor.getConflicts().size(),
133                    visitor.getConflicts().size()
134                ),
135                trn("Conflict during download", "Conflicts during download", visitor.getConflicts().size()),
136                JOptionPane.WARNING_MESSAGE
137        );
138        MapFrame map = MainApplication.getMap();
139        map.conflictDialog.unfurlDialog();
140        map.repaint();
141    }
142
143    protected void downloadParents(long id, OsmPrimitiveType type, ProgressMonitor progressMonitor) throws OsmTransferException {
144        reader = new OsmServerBackreferenceReader(id, type);
145        DataSet ds = reader.parseOsm(progressMonitor.createSubTaskMonitor(1, false));
146        synchronized (this) { // avoid race condition in cancel()
147            reader = null;
148        }
149        Collection<Way> ways = ds.getWays();
150
151        DataSetMerger merger;
152        if (!ways.isEmpty()) {
153            Set<Node> nodes = new HashSet<>();
154            for (Way w: ways) {
155                // Ensure each node is only listed once
156                nodes.addAll(w.getNodes());
157            }
158            // Don't retrieve any nodes we've already grabbed
159            nodes.removeAll(targetLayer.data.getNodes());
160            if (!nodes.isEmpty()) {
161                reader = MultiFetchServerObjectReader.create();
162                ((MultiFetchServerObjectReader) reader).append(nodes);
163                DataSet wayNodes = reader.parseOsm(progressMonitor.createSubTaskMonitor(1, false));
164                synchronized (this) { // avoid race condition in cancel()
165                    reader = null;
166                }
167                merger = new DataSetMerger(ds, wayNodes);
168                merger.merge();
169            }
170        }
171        merger = new DataSetMerger(parents, ds);
172        merger.merge();
173    }
174
175    @Override
176    protected void realRun() throws SAXException, IOException, OsmTransferException {
177        try {
178            progressMonitor.setTicksCount(children.size());
179            int i = 1;
180            for (Entry<Long, OsmPrimitiveType> entry: children.entrySet()) {
181                if (canceled)
182                    return;
183                String msg;
184                switch(entry.getValue()) {
185                case NODE: msg = tr("({0}/{1}) Loading parents of node {2}", i+1, children.size(), entry.getKey()); break;
186                case WAY: msg = tr("({0}/{1}) Loading parents of way {2}", i+1, children.size(), entry.getKey()); break;
187                case RELATION: msg = tr("({0}/{1}) Loading parents of relation {2}", i+1, children.size(), entry.getKey()); break;
188                default: throw new AssertionError();
189                }
190                progressMonitor.subTask(msg);
191                downloadParents(entry.getKey(), entry.getValue(), progressMonitor);
192                i++;
193            }
194        } catch (OsmTransferException e) {
195            if (canceled)
196                return;
197            lastException = e;
198        }
199    }
200}
Note: See TracBrowser for help on using the repository browser.