source: josm/trunk/src/org/openstreetmap/josm/io/OsmServerWriter.java@ 9242

Last change on this file since 9242 was 9231, checked in by Don-vip, 8 years ago

javadoc update

  • Property svn:eol-style set to native
File size: 10.9 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.io;
3
4import static org.openstreetmap.josm.tools.I18n.marktr;
5import static org.openstreetmap.josm.tools.I18n.tr;
6import static org.openstreetmap.josm.tools.I18n.trn;
7
8import java.util.ArrayList;
9import java.util.Collection;
10import java.util.Iterator;
11import java.util.LinkedList;
12import java.util.List;
13
14import org.openstreetmap.josm.data.osm.Changeset;
15import org.openstreetmap.josm.data.osm.OsmPrimitive;
16import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
17import org.openstreetmap.josm.gui.io.UploadStrategySpecification;
18import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
19import org.openstreetmap.josm.gui.progress.ProgressMonitor;
20import org.openstreetmap.josm.tools.CheckParameterUtil;
21
22/**
23 * Class that uploads all changes to the osm server.
24 *
25 * This is done like this: - All objects with id = 0 are uploaded as new, except
26 * those in deleted, which are ignored - All objects in deleted list are
27 * deleted. - All remaining objects with modified flag set are updated.
28 */
29public class OsmServerWriter {
30 /**
31 * This list contains all successfully processed objects. The caller of
32 * upload* has to check this after the call and update its dataset.
33 *
34 * If a server connection error occurs, this may contain fewer entries
35 * than where passed in the list to upload*.
36 */
37 private Collection<OsmPrimitive> processed;
38
39 private static volatile List<OsmServerWritePostprocessor> postprocessors;
40 public static void registerPostprocessor(OsmServerWritePostprocessor pp) {
41 if (postprocessors == null) {
42 postprocessors = new ArrayList<>();
43 }
44 postprocessors.add(pp);
45 }
46
47 public static void unregisterPostprocessor(OsmServerWritePostprocessor pp) {
48 if (postprocessors != null) {
49 postprocessors.remove(pp);
50 }
51 }
52
53 private final OsmApi api = OsmApi.getOsmApi();
54 private boolean canceled;
55
56 private static final int MSECS_PER_SECOND = 1000;
57 private static final int SECONDS_PER_MINUTE = 60;
58 private static final int MSECS_PER_MINUTE = MSECS_PER_SECOND * SECONDS_PER_MINUTE;
59
60 private long uploadStartTime;
61
62 public String timeLeft(int progress, int list_size) {
63 long now = System.currentTimeMillis();
64 long elapsed = now - uploadStartTime;
65 if (elapsed == 0) {
66 elapsed = 1;
67 }
68 double uploads_per_ms = (double) progress / elapsed;
69 double uploads_left = list_size - progress;
70 long ms_left = (long) (uploads_left / uploads_per_ms);
71 long minutes_left = ms_left / MSECS_PER_MINUTE;
72 long seconds_left = (ms_left / MSECS_PER_SECOND) % SECONDS_PER_MINUTE;
73 StringBuilder time_left_str = new StringBuilder().append(minutes_left).append(':');
74 if (seconds_left < 10) {
75 time_left_str.append('0');
76 }
77 return time_left_str.append(seconds_left).toString();
78 }
79
80 /**
81 * Uploads the changes individually. Invokes one API call per uploaded primitmive.
82 *
83 * @param primitives the collection of primitives to upload
84 * @param progressMonitor the progress monitor
85 * @throws OsmTransferException if an exception occurs
86 */
87 protected void uploadChangesIndividually(Collection<? extends OsmPrimitive> primitives, ProgressMonitor progressMonitor)
88 throws OsmTransferException {
89 try {
90 progressMonitor.beginTask(tr("Starting to upload with one request per primitive ..."));
91 progressMonitor.setTicksCount(primitives.size());
92 uploadStartTime = System.currentTimeMillis();
93 for (OsmPrimitive osm : primitives) {
94 int progress = progressMonitor.getTicks();
95 String time_left_str = timeLeft(progress, primitives.size());
96 String msg = "";
97 switch(OsmPrimitiveType.from(osm)) {
98 case NODE: msg = marktr("{0}% ({1}/{2}), {3} left. Uploading node ''{4}'' (id: {5})"); break;
99 case WAY: msg = marktr("{0}% ({1}/{2}), {3} left. Uploading way ''{4}'' (id: {5})"); break;
100 case RELATION: msg = marktr("{0}% ({1}/{2}), {3} left. Uploading relation ''{4}'' (id: {5})"); break;
101 }
102 progressMonitor.subTask(
103 tr(msg,
104 Math.round(100.0*progress/primitives.size()),
105 progress,
106 primitives.size(),
107 time_left_str,
108 osm.getName() == null ? osm.getId() : osm.getName(),
109 osm.getId()));
110 makeApiRequest(osm, progressMonitor);
111 processed.add(osm);
112 progressMonitor.worked(1);
113 }
114 } catch (OsmTransferException e) {
115 throw e;
116 } catch (Exception e) {
117 throw new OsmTransferException(e);
118 } finally {
119 progressMonitor.finishTask();
120 }
121 }
122
123 /**
124 * Upload all changes in one diff upload
125 *
126 * @param primitives the collection of primitives to upload
127 * @param progressMonitor the progress monitor
128 * @throws OsmTransferException if an exception occurs
129 */
130 protected void uploadChangesAsDiffUpload(Collection<? extends OsmPrimitive> primitives, ProgressMonitor progressMonitor)
131 throws OsmTransferException {
132 try {
133 progressMonitor.beginTask(tr("Starting to upload in one request ..."));
134 processed.addAll(api.uploadDiff(primitives, progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false)));
135 } catch (OsmTransferException e) {
136 throw e;
137 } finally {
138 progressMonitor.finishTask();
139 }
140 }
141
142 /**
143 * Upload all changes in one diff upload
144 *
145 * @param primitives the collection of primitives to upload
146 * @param progressMonitor the progress monitor
147 * @param chunkSize the size of the individual upload chunks. &gt; 0 required.
148 * @throws IllegalArgumentException if chunkSize &lt;= 0
149 * @throws OsmTransferException if an exception occurs
150 */
151 protected void uploadChangesInChunks(Collection<? extends OsmPrimitive> primitives, ProgressMonitor progressMonitor, int chunkSize)
152 throws OsmTransferException, IllegalArgumentException {
153 if (chunkSize <= 0)
154 throw new IllegalArgumentException(tr("Value >0 expected for parameter ''{0}'', got {1}", "chunkSize", chunkSize));
155 try {
156 progressMonitor.beginTask(tr("Starting to upload in chunks..."));
157 List<OsmPrimitive> chunk = new ArrayList<>(chunkSize);
158 Iterator<? extends OsmPrimitive> it = primitives.iterator();
159 int numChunks = (int) Math.ceil((double) primitives.size() / (double) chunkSize);
160 int i = 0;
161 while (it.hasNext()) {
162 i++;
163 if (canceled) return;
164 int j = 0;
165 chunk.clear();
166 while (it.hasNext() && j < chunkSize) {
167 if (canceled) return;
168 j++;
169 chunk.add(it.next());
170 }
171 progressMonitor.setCustomText(
172 trn("({0}/{1}) Uploading {2} object...",
173 "({0}/{1}) Uploading {2} objects...",
174 chunk.size(), i, numChunks, chunk.size()));
175 processed.addAll(api.uploadDiff(chunk, progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false)));
176 }
177 } catch (OsmTransferException e) {
178 throw e;
179 } finally {
180 progressMonitor.finishTask();
181 }
182 }
183
184 /**
185 * Send the dataset to the server.
186 *
187 * @param strategy the upload strategy. Must not be null.
188 * @param primitives list of objects to send
189 * @param changeset the changeset the data is uploaded to. Must not be null.
190 * @param monitor the progress monitor. If null, assumes {@link NullProgressMonitor#INSTANCE}
191 * @throws IllegalArgumentException if changeset is null
192 * @throws IllegalArgumentException if strategy is null
193 * @throws OsmTransferException if something goes wrong
194 */
195 public void uploadOsm(UploadStrategySpecification strategy, Collection<? extends OsmPrimitive> primitives,
196 Changeset changeset, ProgressMonitor monitor) throws OsmTransferException {
197 CheckParameterUtil.ensureParameterNotNull(changeset, "changeset");
198 processed = new LinkedList<>();
199 monitor = monitor == null ? NullProgressMonitor.INSTANCE : monitor;
200 monitor.beginTask(tr("Uploading data ..."));
201 try {
202 api.initialize(monitor);
203 // check whether we can use diff upload
204 if (changeset.getId() == 0) {
205 api.openChangeset(changeset, monitor.createSubTaskMonitor(0, false));
206 } else {
207 api.updateChangeset(changeset, monitor.createSubTaskMonitor(0, false));
208 }
209 api.setChangeset(changeset);
210 switch(strategy.getStrategy()) {
211 case SINGLE_REQUEST_STRATEGY:
212 uploadChangesAsDiffUpload(primitives, monitor.createSubTaskMonitor(0, false));
213 break;
214 case INDIVIDUAL_OBJECTS_STRATEGY:
215 uploadChangesIndividually(primitives, monitor.createSubTaskMonitor(0, false));
216 break;
217 case CHUNKED_DATASET_STRATEGY:
218 uploadChangesInChunks(primitives, monitor.createSubTaskMonitor(0, false), strategy.getChunkSize());
219 break;
220 }
221 } catch (OsmTransferException e) {
222 throw e;
223 } finally {
224 executePostprocessors(monitor);
225 monitor.finishTask();
226 api.setChangeset(null);
227 }
228 }
229
230 void makeApiRequest(OsmPrimitive osm, ProgressMonitor progressMonitor) throws OsmTransferException {
231 if (osm.isDeleted()) {
232 api.deletePrimitive(osm, progressMonitor);
233 } else if (osm.isNew()) {
234 api.createPrimitive(osm, progressMonitor);
235 } else {
236 api.modifyPrimitive(osm, progressMonitor);
237 }
238 }
239
240 public void cancel() {
241 this.canceled = true;
242 if (api != null) {
243 api.cancel();
244 }
245 }
246
247 /**
248 * Replies the collection of successfully processed primitives
249 *
250 * @return the collection of successfully processed primitives
251 */
252 public Collection<OsmPrimitive> getProcessedPrimitives() {
253 return processed;
254 }
255
256 /**
257 * Calls all registered upload postprocessors.
258 * @param pm progress monitor
259 */
260 public void executePostprocessors(ProgressMonitor pm) {
261 if (postprocessors != null) {
262 for (OsmServerWritePostprocessor pp : postprocessors) {
263 pp.postprocessUploadedPrimitives(processed, pm);
264 }
265 }
266 }
267}
Note: See TracBrowser for help on using the repository browser.