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 }