Ticket #8509: async_v5.patch
| File async_v5.patch, 16.0 KB (added by , 8 years ago) |
|---|
-
src/org/openstreetmap/josm/actions/UploadAction.java
9 9 import java.util.LinkedList; 10 10 import java.util.List; 11 11 import java.util.Map; 12 import java.util.Optional; 12 13 13 14 import javax.swing.JOptionPane; 14 15 … … 24 25 import org.openstreetmap.josm.data.osm.Changeset; 25 26 import org.openstreetmap.josm.gui.HelpAwareOptionPane; 26 27 import org.openstreetmap.josm.gui.MainApplication; 28 import org.openstreetmap.josm.gui.io.AsynchronousUploadPrimitivesTask; 27 29 import org.openstreetmap.josm.gui.io.UploadDialog; 28 30 import org.openstreetmap.josm.gui.io.UploadPrimitivesTask; 29 31 import org.openstreetmap.josm.gui.layer.AbstractModifiableLayer; … … 57 59 private static final List<UploadHook> UPLOAD_HOOKS = new LinkedList<>(); 58 60 private static final List<UploadHook> LATE_UPLOAD_HOOKS = new LinkedList<>(); 59 61 62 private static final String IS_ASYNC_UPLOAD_ENABLED = "asynchronous.upload"; 63 60 64 static { 61 65 /** 62 66 * Calls validator before upload. … … 257 261 hook.modifyChangesetTags(changesetTags); 258 262 } 259 263 260 MainApplication.worker.execute( 261 new UploadPrimitivesTask( 262 UploadDialog.getUploadDialog().getUploadStrategySpecification(), 263 layer, 264 apiData, 265 cs 266 ) 267 ); 264 if (Main.pref.get(IS_ASYNC_UPLOAD_ENABLED).isEmpty() || 265 !Main.pref.get(IS_ASYNC_UPLOAD_ENABLED).equalsIgnoreCase("disabled")) { 266 Optional <AsynchronousUploadPrimitivesTask> asyncUploadTask = AsynchronousUploadPrimitivesTask.createAsynchronousUploadTask( 267 UploadDialog.getUploadDialog().getUploadStrategySpecification(), 268 layer, 269 apiData, 270 cs); 271 272 if (asyncUploadTask.isPresent()) { 273 MainApplication.worker.execute(asyncUploadTask.get()); 274 } 275 } else { 276 MainApplication.worker.execute( 277 new UploadPrimitivesTask( 278 UploadDialog.getUploadDialog().getUploadStrategySpecification(), 279 layer, 280 apiData, 281 cs)); 282 } 268 283 } 269 284 270 285 @Override -
src/org/openstreetmap/josm/gui/io/AsynchronousUploadPrimitivesTask.java
1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.gui.io; 3 4 import org.openstreetmap.josm.data.APIDataSet; 5 import org.openstreetmap.josm.data.osm.Changeset; 6 import org.openstreetmap.josm.gui.MainApplication; 7 import org.openstreetmap.josm.gui.dialogs.LayerListDialog; 8 import org.openstreetmap.josm.gui.layer.OsmDataLayer; 9 import org.openstreetmap.josm.gui.progress.ProgressTaskId; 10 import org.openstreetmap.josm.gui.util.GuiHelper; 11 import org.openstreetmap.josm.io.UploadStrategySpecification; 12 13 import javax.swing.*; 14 import java.awt.*; 15 import java.util.Optional; 16 17 import static org.openstreetmap.josm.tools.I18n.tr; 18 19 /** 20 * Task for uploading primitives using background worker threads 21 * @author udit 22 */ 23 public class AsynchronousUploadPrimitivesTask extends UploadPrimitivesTask { 24 25 /** 26 * Static instance 27 */ 28 private static AsynchronousUploadPrimitivesTask asynchronousUploadPrimitivesTask = null; 29 30 /** 31 * Member fields 32 */ 33 private final ProgressTaskId taskId; 34 private final OsmDataLayer uploadDataLayer; 35 36 /** 37 * Private constructor to restrict creating more Asynchronous upload tasks 38 * 39 * @param uploadStrategySpecification 40 * @param osmDataLayer 41 * @param apiDataSet 42 * @param changeset 43 */ 44 private AsynchronousUploadPrimitivesTask(UploadStrategySpecification uploadStrategySpecification, OsmDataLayer osmDataLayer, APIDataSet apiDataSet, Changeset changeset) { 45 super(uploadStrategySpecification, 46 osmDataLayer, 47 apiDataSet, 48 changeset); 49 50 uploadDataLayer = osmDataLayer; 51 // Create a ProgressTaskId for background upload 52 taskId = new ProgressTaskId("core", "async-upload"); 53 } 54 55 /** 56 * Creates an instance of AsynchronousUploadPrimitiveTask 57 * 58 * @param uploadStrategySpecification 59 * @param dataLayer 60 * @param apiDataSet 61 * @param changeset 62 * @return Optional<AsynchronousUploadPrimitivesTask> 63 */ 64 public static Optional<AsynchronousUploadPrimitivesTask> createAsynchronousUploadTask 65 (UploadStrategySpecification uploadStrategySpecification, 66 OsmDataLayer dataLayer, APIDataSet apiDataSet, Changeset changeset) { 67 synchronized (AsynchronousUploadPrimitivesTask.class) { 68 if (asynchronousUploadPrimitivesTask != null) { 69 if (!GraphicsEnvironment.isHeadless()) { 70 GuiHelper.runInEDTAndWait(() -> 71 JOptionPane.showMessageDialog(MainApplication.parent, 72 tr("A background upload is already in progress. Kindly wait for it to finish before uploading new changes"))); 73 } 74 return Optional.empty(); 75 } else { 76 // Create an asynchronous upload task 77 asynchronousUploadPrimitivesTask = new AsynchronousUploadPrimitivesTask( 78 uploadStrategySpecification, 79 dataLayer, 80 apiDataSet, 81 changeset); 82 return Optional.ofNullable(asynchronousUploadPrimitivesTask); 83 } 84 } 85 } 86 87 /** 88 * Get the current upload task 89 * @return Optional<AsynchronousUploadPrimitivesTask> 90 */ 91 public static Optional<AsynchronousUploadPrimitivesTask> getCurrentAsynchronousUploadTask () { 92 return Optional.ofNullable(asynchronousUploadPrimitivesTask); 93 } 94 95 @Override 96 public ProgressTaskId canRunInBackground() { 97 return taskId; 98 } 99 100 @Override 101 protected void realRun() { 102 // Lock the data layer before upload in EDT 103 GuiHelper.runInEDTAndWait(() -> { 104 // Remove the commands from the undo stack 105 MainApplication.undoRedo.clean(uploadDataLayer.data); 106 MainApplication.getLayerManager().prepareLayerForUpload(uploadDataLayer); 107 108 // Repainting the Layer List dialog to update the icon of the active layer 109 LayerListDialog.getInstance().repaint(); 110 }); 111 super.realRun(); 112 } 113 114 @Override 115 protected void cancel() { 116 super.cancel(); 117 asynchronousUploadPrimitivesTask = null; 118 } 119 120 @Override 121 protected void finish() { 122 try { 123 // Unlock the data layer in EDT 124 GuiHelper.runInEDTAndWait(() -> { 125 MainApplication.getLayerManager().processLayerAfterUpload(uploadDataLayer); 126 LayerListDialog.getInstance().repaint(); 127 }); 128 super.finish(); 129 } finally { 130 asynchronousUploadPrimitivesTask = null; 131 } 132 } 133 } 134 No newline at end of file -
src/org/openstreetmap/josm/gui/layer/MainLayerManager.java
1 1 // License: GPL. For details, see LICENSE file. 2 2 package org.openstreetmap.josm.gui.layer; 3 3 4 import org.openstreetmap.josm.data.osm.DataSet; 5 import org.openstreetmap.josm.gui.MainApplication; 6 import org.openstreetmap.josm.gui.util.GuiHelper; 7 8 import javax.swing.*; 4 9 import java.util.ArrayList; 5 10 import java.util.Collection; 6 11 import java.util.List; … … 7 12 import java.util.ListIterator; 8 13 import java.util.concurrent.CopyOnWriteArrayList; 9 14 10 import org.openstreetmap.josm.data.osm.DataSet; 11 import org.openstreetmap.josm.gui.util.GuiHelper; 15 import static org.openstreetmap.josm.tools.I18n.tr; 12 16 13 17 /** 14 18 * This class extends the layer manager by adding an active and an edit layer. … … 205 209 } 206 210 207 211 /** 208 * Set the active layer. If the layer is an OsmDataLayer, the edit layer is also changed. 212 * Set the active layer iff the layer is not read only. 213 * If the layer is an OsmDataLayer, the edit layer is also changed. 209 214 * @param layer The active layer. 210 215 */ 211 216 public void setActiveLayer(final Layer layer) { 212 217 // we force this on to the EDT Thread to make events fire from there. 213 218 // The synchronization lock needs to be held by the EDT. 214 GuiHelper.runInEDTAndWaitWithException(() -> realSetActiveLayer(layer)); 219 if (layer instanceof OsmDataLayer && ((OsmDataLayer) layer).isReadOnly()) { 220 GuiHelper.runInEDT(() -> 221 JOptionPane.showMessageDialog( 222 MainApplication.parent, 223 tr("Trying to set a read only data layer as edit layer"), 224 tr("Warning"), 225 JOptionPane.WARNING_MESSAGE)); 226 } else { 227 GuiHelper.runInEDTAndWaitWithException(() -> realSetActiveLayer(layer)); 228 } 215 229 } 216 230 217 231 protected synchronized void realSetActiveLayer(final Layer layer) { … … 309 323 * @return the currently active layer (may be null) 310 324 */ 311 325 public synchronized Layer getActiveLayer() { 312 return activeLayer; 326 if (activeLayer instanceof OsmDataLayer) { 327 if (!((OsmDataLayer)activeLayer).isReadOnly()) { 328 return activeLayer; 329 } else { 330 return null; 331 } 332 } else { 333 return activeLayer; 334 } 313 335 } 314 336 315 337 /** … … 318 340 * @return the current edit layer. May be null. 319 341 */ 320 342 public synchronized OsmDataLayer getEditLayer() { 321 return editLayer; 343 if (editLayer != null && !editLayer.isReadOnly()) 344 return editLayer; 345 else 346 return null; 322 347 } 323 348 324 349 /** … … 378 403 activeLayerChangeListeners.clear(); 379 404 layerAvailabilityListeners.clear(); 380 405 } 406 407 public void prepareLayerForUpload (OsmDataLayer layer) { 408 409 GuiHelper.assertCallFromEdt(); 410 layer.setReadOnly(); 411 412 // Reset only the edit layer as empty 413 if (editLayer == layer) { 414 ActiveLayerChangeEvent activeLayerChangeEvent = new ActiveLayerChangeEvent(this, editLayer, activeLayer); 415 editLayer = null; 416 fireActiveLayerChange(activeLayerChangeEvent); 417 } 418 } 419 420 public void processLayerAfterUpload (OsmDataLayer layer) { 421 GuiHelper.assertCallFromEdt(); 422 layer.unsetReadOnly(); 423 424 // Set the layer as edit layer 425 // iff the edit layer is empty. 426 if (editLayer == null) { 427 ActiveLayerChangeEvent layerChangeEvent = new ActiveLayerChangeEvent(this, editLayer, activeLayer); 428 editLayer = layer; 429 fireActiveLayerChange(layerChangeEvent); 430 } 431 } 381 432 } -
src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java
31 31 import java.util.Map; 32 32 import java.util.Set; 33 33 import java.util.concurrent.CopyOnWriteArrayList; 34 import java.util.concurrent.atomic.AtomicBoolean; 34 35 import java.util.concurrent.atomic.AtomicInteger; 35 36 import java.util.regex.Pattern; 36 37 … … 129 130 130 131 private boolean requiresSaveToFile; 131 132 private boolean requiresUploadToServer; 133 private final AtomicBoolean isReadOnly = new AtomicBoolean(false); 132 134 133 135 /** 134 136 * List of validation errors in this layer. … … 420 422 if (isUploadDiscouraged() || data.getUploadPolicy() == UploadPolicy.BLOCKED) { 421 423 base.addOverlay(new ImageOverlay(new ImageProvider("warning-small"), 0.5, 0.5, 1.0, 1.0)); 422 424 } 425 426 if (isReadOnly()) { 427 // If the layer is read only then change the default icon to a clock 428 base = new ImageProvider("clock").setMaxSize(ImageSizes.LAYER); 429 } 423 430 return base.get(); 424 431 } 425 432 … … 1142 1149 } 1143 1150 super.setName(name); 1144 1151 } 1152 1153 public void setReadOnly() { 1154 if (!isReadOnly.compareAndSet(false, true)) { 1155 Logging.warn("Trying to set readOnly flag on a readOnly layer ", this.getName()); 1156 } 1157 } 1158 1159 public void unsetReadOnly() { 1160 if (!isReadOnly.compareAndSet(true, false)) { 1161 Logging.warn("Trying to unset readOnly flag on a non-readOnly layer ", this.getName()); 1162 } 1163 } 1164 1165 public boolean isReadOnly() { 1166 return isReadOnly.get(); 1167 } 1145 1168 } -
test/unit/org/openstreetmap/josm/gui/io/AsynchronousUploadPrimitivesTaskTest.java
1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.gui.io; 3 4 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 5 import org.junit.*; 6 import org.openstreetmap.josm.data.APIDataSet; 7 import org.openstreetmap.josm.data.coor.LatLon; 8 import org.openstreetmap.josm.data.osm.Changeset; 9 import org.openstreetmap.josm.data.osm.DataSet; 10 import org.openstreetmap.josm.data.osm.Node; 11 import org.openstreetmap.josm.data.osm.Way; 12 import org.openstreetmap.josm.gui.layer.OsmDataLayer; 13 import org.openstreetmap.josm.io.UploadStrategySpecification; 14 import org.openstreetmap.josm.testutils.JOSMTestRules; 15 16 import java.util.Optional; 17 18 public class AsynchronousUploadPrimitivesTaskTest { 19 20 private UploadStrategySpecification strategy; 21 private OsmDataLayer layer; 22 private APIDataSet toUpload; 23 private Changeset changeset; 24 private AsynchronousUploadPrimitivesTask uploadPrimitivesTask; 25 26 /** 27 * Setup tests 28 */ 29 @Rule 30 @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD") 31 public JOSMTestRules test = new JOSMTestRules(); 32 33 @Before 34 public void bootStrap() { 35 DataSet dataSet = new DataSet(); 36 Node node1 = new Node(); 37 Node node2 = new Node(); 38 node1.setCoor(new LatLon(0, 0)); 39 node2.setCoor(new LatLon(30, 30)); 40 Way way = new Way(); 41 way.addNode(node1); 42 way.addNode(node2); 43 dataSet.addPrimitive(node1); 44 dataSet.addPrimitive(node2); 45 dataSet.addPrimitive(way); 46 47 toUpload = new APIDataSet(dataSet); 48 layer = new OsmDataLayer(dataSet, "uploadTest", null); 49 strategy = new UploadStrategySpecification(); 50 changeset = new Changeset(); 51 uploadPrimitivesTask = AsynchronousUploadPrimitivesTask.createAsynchronousUploadTask(strategy, layer, toUpload, changeset).get(); 52 } 53 54 @After 55 public void tearDown () { 56 toUpload = null; 57 layer = null; 58 strategy = null; 59 changeset = null; 60 uploadPrimitivesTask = null; 61 } 62 63 @Test 64 public void testSingleUploadInstance () { 65 Optional<AsynchronousUploadPrimitivesTask> task = AsynchronousUploadPrimitivesTask.createAsynchronousUploadTask(strategy, layer, toUpload, changeset); 66 Assert.assertNotNull(uploadPrimitivesTask); 67 Assert.assertFalse(task.isPresent()); 68 } 69 }
