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

Last change on this file since 13215 was 12743, checked in by Don-vip, 7 years ago

see #15229 - see #15182 - deprecate gui.JosmUserIdentityManager - replaced by data.UserIdentityManager

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