001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.dialogs.changeset; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.awt.Component; 007import java.io.IOException; 008import java.lang.reflect.InvocationTargetException; 009import java.util.Collection; 010import java.util.Collections; 011import java.util.HashSet; 012import java.util.Set; 013 014import javax.swing.SwingUtilities; 015 016import org.openstreetmap.josm.Main; 017import org.openstreetmap.josm.data.osm.Changeset; 018import org.openstreetmap.josm.data.osm.ChangesetCache; 019import org.openstreetmap.josm.gui.ExceptionDialogUtil; 020import org.openstreetmap.josm.gui.PleaseWaitRunnable; 021import org.openstreetmap.josm.io.OsmServerChangesetReader; 022import org.openstreetmap.josm.io.OsmTransferException; 023import org.openstreetmap.josm.tools.BugReportExceptionHandler; 024import org.openstreetmap.josm.tools.CheckParameterUtil; 025import org.openstreetmap.josm.tools.ExceptionUtil; 026import 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 */ 036public 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 org.openstreetmap.josm.gui.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 org.openstreetmap.josm.gui.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 org.openstreetmap.josm.gui.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 org.openstreetmap.josm.gui.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 @Override 150 public void run() { 151 ChangesetCache.getInstance().update(downloadedChangesets); 152 } 153 }; 154 155 if (SwingUtilities.isEventDispatchThread()) { 156 r.run(); 157 } else { 158 try { 159 SwingUtilities.invokeAndWait(r); 160 } catch(InterruptedException e) { 161 Main.warn("InterruptedException in "+getClass().getSimpleName()+" while updating changeset cache"); 162 } catch(InvocationTargetException e) { 163 Throwable t = e.getTargetException(); 164 if (t instanceof RuntimeException) { 165 BugReportExceptionHandler.handleException(t); 166 } else if (t instanceof Exception){ 167 ExceptionUtil.explainException(e); 168 } else { 169 BugReportExceptionHandler.handleException(t); 170 } 171 } 172 } 173 } 174 175 @Override 176 protected void realRun() throws SAXException, IOException, OsmTransferException { 177 try { 178 synchronized (this) { 179 reader = new OsmServerChangesetReader(); 180 } 181 downloadedChangesets = new HashSet<Changeset>(); 182 downloadedChangesets.addAll(reader.readChangesets(idsToDownload, getProgressMonitor().createSubTaskMonitor(0, false))); 183 } catch(OsmTransferException e) { 184 if (canceled) 185 // ignore exception if canceled 186 return; 187 // remember other exceptions 188 lastException = e; 189 } 190 } 191 192 /* ------------------------------------------------------------------------------- */ 193 /* interface ChangesetDownloadTask */ 194 /* ------------------------------------------------------------------------------- */ 195 @Override 196 public Set<Changeset> getDownloadedChangesets() { 197 return downloadedChangesets; 198 } 199 200 @Override 201 public boolean isCanceled() { 202 return canceled; 203 } 204 205 @Override 206 public boolean isFailed() { 207 return lastException != null; 208 } 209}