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

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

sonar - squid:S2221 - "Exception" should not be caught when not required by called methods

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