001 // License: GPL. For details, see LICENSE file. 002 package org.openstreetmap.josm.gui.dialogs.changeset; 003 004 import static org.openstreetmap.josm.tools.I18n.tr; 005 006 import java.awt.Component; 007 import java.io.IOException; 008 import java.lang.reflect.InvocationTargetException; 009 import java.util.Collection; 010 import java.util.Collections; 011 import java.util.HashSet; 012 import java.util.Set; 013 014 import javax.swing.SwingUtilities; 015 016 import org.openstreetmap.josm.Main; 017 import org.openstreetmap.josm.data.osm.Changeset; 018 import org.openstreetmap.josm.data.osm.ChangesetCache; 019 import org.openstreetmap.josm.gui.ExceptionDialogUtil; 020 import org.openstreetmap.josm.gui.PleaseWaitRunnable; 021 import org.openstreetmap.josm.io.OsmServerChangesetReader; 022 import org.openstreetmap.josm.io.OsmTransferException; 023 import org.openstreetmap.josm.tools.BugReportExceptionHandler; 024 import org.openstreetmap.josm.tools.CheckParameterUtil; 025 import org.openstreetmap.josm.tools.ExceptionUtil; 026 import org.xml.sax.SAXException; 027 028 /** 029 * This is an asynchronous task for downloading a collection of changests from the OSM 030 * server. 031 * 032 * The task only downloads the changeset properties without the changeset content. It 033 * updates the global {@link ChangesetCache}. 034 * 035 */ 036 public class ChangesetHeaderDownloadTask extends PleaseWaitRunnable implements ChangesetDownloadTask{ 037 038 /** 039 * Builds a download task from for a collection of changesets. 040 * 041 * Ignores null values and changesets with {@link Changeset#isNew()} == true. 042 * 043 * @param changesets the collection of changesets. Assumes an empty collection if null. 044 * @return the download task 045 */ 046 static public ChangesetHeaderDownloadTask buildTaskForChangesets(Collection<Changeset> changesets) { 047 return buildTaskForChangesets(Main.parent, changesets); 048 } 049 050 /** 051 * Builds a download task from for a collection of changesets. 052 * 053 * Ignores null values and changesets with {@link Changeset#isNew()} == true. 054 * 055 * @param parent the parent component relative to which the {@link PleaseWaitDialog} is displayed. 056 * Must not be null. 057 * @param changesets the collection of changesets. Assumes an empty collection if null. 058 * @return the download task 059 * @throws IllegalArgumentException thrown if parent is null 060 */ 061 static public ChangesetHeaderDownloadTask buildTaskForChangesets(Component parent, Collection<Changeset> changesets) { 062 CheckParameterUtil.ensureParameterNotNull(parent, "parent"); 063 if (changesets == null) { 064 changesets = Collections.emptyList(); 065 } 066 067 HashSet<Integer> ids = new HashSet<Integer>(); 068 for (Changeset cs: changesets) { 069 if (cs == null || cs.isNew()) { 070 continue; 071 } 072 ids.add(cs.getId()); 073 } 074 if (parent == null) 075 return new ChangesetHeaderDownloadTask(ids); 076 else 077 return new ChangesetHeaderDownloadTask(parent, ids); 078 079 } 080 081 private Set<Integer> idsToDownload; 082 private OsmServerChangesetReader reader; 083 private boolean canceled; 084 private Exception lastException; 085 private Set<Changeset> downloadedChangesets; 086 087 protected void init(Collection<Integer> ids) { 088 if (ids == null) { 089 ids = Collections.emptyList(); 090 } 091 idsToDownload = new HashSet<Integer>(); 092 if (ids == null || ids.isEmpty()) 093 return; 094 for (int id: ids) { 095 if (id <= 0) { 096 continue; 097 } 098 idsToDownload.add(id); 099 } 100 } 101 102 /** 103 * Creates the download task for a collection of changeset ids. Uses a {@link PleaseWaitDialog} 104 * whose parent is {@link Main#parent}. 105 * 106 * Null ids or or ids <= 0 in the id collection are ignored. 107 * 108 * @param ids the collection of ids. Empty collection assumed if null. 109 */ 110 public ChangesetHeaderDownloadTask(Collection<Integer> ids) { 111 // parent for dialog is Main.parent 112 super(tr("Download changesets"), false /* don't ignore exceptions */); 113 init(ids); 114 } 115 116 /** 117 * Creates the download task for a collection of changeset ids. Uses a {@link PleaseWaitDialog} 118 * whose parent is the parent window of <code>dialogParent</code>. 119 * 120 * Null ids or or ids <= 0 in the id collection are ignored. 121 * 122 * @param dialogParent the parent reference component for the {@link PleaseWaitDialog}. Must not be null. 123 * @param ids the collection of ids. Empty collection assumed if null. 124 * @throws IllegalArgumentException thrown if dialogParent is null 125 */ 126 public ChangesetHeaderDownloadTask(Component dialogParent, Collection<Integer> ids) throws IllegalArgumentException{ 127 super(dialogParent,tr("Download changesets"), false /* don't ignore exceptions */); 128 init(ids); 129 } 130 131 @Override 132 protected void cancel() { 133 canceled = true; 134 synchronized (this) { 135 if (reader != null) { 136 reader.cancel(); 137 } 138 } 139 } 140 141 @Override 142 protected void finish() { 143 if (canceled) 144 return; 145 if (lastException != null) { 146 ExceptionDialogUtil.explainException(lastException); 147 } 148 Runnable r = new Runnable() { 149 public void run() { 150 ChangesetCache.getInstance().update(downloadedChangesets); 151 } 152 }; 153 154 if (SwingUtilities.isEventDispatchThread()) { 155 r.run(); 156 } else { 157 try { 158 SwingUtilities.invokeAndWait(r); 159 } catch(InterruptedException e) { 160 e.printStackTrace(); 161 } catch(InvocationTargetException e) { 162 Throwable t = e.getTargetException(); 163 if (t instanceof RuntimeException) { 164 BugReportExceptionHandler.handleException(t); 165 } else if (t instanceof Exception){ 166 ExceptionUtil.explainException(e); 167 } else { 168 BugReportExceptionHandler.handleException(t); 169 } 170 } 171 } 172 } 173 174 @Override 175 protected void realRun() throws SAXException, IOException, OsmTransferException { 176 try { 177 synchronized (this) { 178 reader = new OsmServerChangesetReader(); 179 } 180 downloadedChangesets = new HashSet<Changeset>(); 181 downloadedChangesets.addAll(reader.readChangesets(idsToDownload, getProgressMonitor().createSubTaskMonitor(0, false))); 182 } catch(OsmTransferException e) { 183 if (canceled) 184 // ignore exception if canceled 185 return; 186 // remember other exceptions 187 lastException = e; 188 } 189 } 190 191 /* ------------------------------------------------------------------------------- */ 192 /* interface ChangesetDownloadTask */ 193 /* ------------------------------------------------------------------------------- */ 194 public Set<Changeset> getDownloadedChangesets() { 195 return downloadedChangesets; 196 } 197 198 public boolean isCanceled() { 199 return canceled; 200 } 201 202 public boolean isFailed() { 203 return lastException != null; 204 } 205 }