001 // License: GPL. For details, see LICENSE file.
002 package org.openstreetmap.josm.gui.dialogs.changeset.query;
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.HashSet;
010 import java.util.Set;
011
012 import javax.swing.JOptionPane;
013 import javax.swing.SwingUtilities;
014
015 import org.openstreetmap.josm.Main;
016 import org.openstreetmap.josm.data.osm.Changeset;
017 import org.openstreetmap.josm.data.osm.ChangesetCache;
018 import org.openstreetmap.josm.data.osm.UserInfo;
019 import org.openstreetmap.josm.gui.JosmUserIdentityManager;
020 import org.openstreetmap.josm.gui.PleaseWaitRunnable;
021 import org.openstreetmap.josm.gui.dialogs.changeset.ChangesetDownloadTask;
022 import org.openstreetmap.josm.gui.util.GuiHelper;
023 import org.openstreetmap.josm.io.ChangesetQuery;
024 import org.openstreetmap.josm.io.OsmServerChangesetReader;
025 import org.openstreetmap.josm.io.OsmServerUserInfoReader;
026 import org.openstreetmap.josm.io.OsmTransferCanceledException;
027 import org.openstreetmap.josm.io.OsmTransferException;
028 import org.openstreetmap.josm.tools.BugReportExceptionHandler;
029 import org.openstreetmap.josm.tools.CheckParameterUtil;
030 import org.openstreetmap.josm.tools.ExceptionUtil;
031 import org.xml.sax.SAXException;
032
033 /**
034 * Asynchronous task to send a changeset query to the OSM API.
035 *
036 */
037 public class ChangesetQueryTask extends PleaseWaitRunnable implements ChangesetDownloadTask{
038
039 /** the changeset query */
040 private ChangesetQuery query;
041 /** true if the task was canceled */
042 private boolean canceled;
043 /** the set of downloaded changesets */
044 private Set<Changeset> downloadedChangesets;
045 /** the last exception remembered, if any */
046 private Exception lastException;
047 /** the reader object used to read information about the current user from the API */
048 private OsmServerUserInfoReader userInfoReader;
049 /** the reader object used to submit the changeset query to the API */
050 private OsmServerChangesetReader changesetReader;
051
052 /**
053 * Creates the task.
054 *
055 * @param query the query to submit to the OSM server. Must not be null.
056 * @throws IllegalArgumentException thrown if query is null.
057 */
058 public ChangesetQueryTask(ChangesetQuery query) throws IllegalArgumentException {
059 super(tr("Querying and downloading changesets",false /* don't ignore exceptions */));
060 CheckParameterUtil.ensureParameterNotNull(query, "query");
061 this.query = query;
062 }
063
064 /**
065 * Creates the task.
066 *
067 * @param parent the parent component relative to which the {@link PleaseWaitDialog} is displayed.
068 * Must not be null.
069 * @param query the query to submit to the OSM server. Must not be null.
070 * @throws IllegalArgumentException thrown if query is null.
071 * @throws IllegalArgumentException thrown if parent is null
072 */
073 public ChangesetQueryTask(Component parent, ChangesetQuery query) throws IllegalArgumentException {
074 super(parent, tr("Querying and downloading changesets"), false /* don't ignore exceptions */);
075 CheckParameterUtil.ensureParameterNotNull(query, "query");
076 this.query = query;
077 }
078
079 @Override
080 protected void cancel() {
081 canceled = true;
082 synchronized(this) {
083 if (userInfoReader != null) {
084 userInfoReader.cancel();
085 }
086 }
087 synchronized(this) {
088 if (changesetReader != null) {
089 changesetReader.cancel();
090 }
091 }
092 }
093
094 @Override
095 protected void finish() {
096 if (canceled) return;
097 if (lastException != null) {
098 GuiHelper.runInEDTAndWait(new Runnable() {
099 private final Component parent = progressMonitor != null ? progressMonitor.getWindowParent() : null;
100 @Override
101 public void run() {
102 JOptionPane.showMessageDialog(
103 parent != null ? parent : Main.parent,
104 ExceptionUtil.explainException(lastException),
105 tr("Errors during download"),
106 JOptionPane.ERROR_MESSAGE);
107 }
108 });
109 return;
110 }
111
112 // update the global changeset cache with the downloaded changesets;
113 // this will trigger change events which views are listening to. They
114 // will update their views accordingly.
115 //
116 // Run on the EDT because UI updates are triggered.
117 //
118 Runnable r = new Runnable() {
119 public void run() {
120 ChangesetCache.getInstance().update(downloadedChangesets);
121 }
122 };
123 if (SwingUtilities.isEventDispatchThread()) {
124 r.run();
125 } else {
126 try {
127 SwingUtilities.invokeAndWait(r);
128 } catch(InterruptedException e) {
129 e.printStackTrace();
130 } catch(InvocationTargetException e) {
131 Throwable t = e.getTargetException();
132 if (t instanceof RuntimeException) {
133 BugReportExceptionHandler.handleException(t);
134 } else if (t instanceof Exception){
135 ExceptionUtil.explainException(e);
136 } else {
137 BugReportExceptionHandler.handleException(t);
138 }
139 }
140 }
141 }
142
143 /**
144 * Tries to fully identify the current JOSM user
145 *
146 * @throws OsmTransferException thrown if something went wrong
147 */
148 protected void fullyIdentifyCurrentUser() throws OsmTransferException {
149 getProgressMonitor().indeterminateSubTask(tr("Determine user id for current user..."));
150
151 synchronized(this) {
152 userInfoReader = new OsmServerUserInfoReader();
153 }
154 UserInfo info = userInfoReader.fetchUserInfo(getProgressMonitor().createSubTaskMonitor(1,false));
155 synchronized(this) {
156 userInfoReader = null;
157 }
158 JosmUserIdentityManager im = JosmUserIdentityManager.getInstance();
159 im.setFullyIdentified(im.getUserName(), info);
160 }
161
162 @Override
163 protected void realRun() throws SAXException, IOException, OsmTransferException {
164 try {
165 JosmUserIdentityManager im = JosmUserIdentityManager.getInstance();
166 if (query.isRestrictedToPartiallyIdentifiedUser() && im.isCurrentUser(query.getUserName())) {
167 // if we query changesets for the current user, make sure we query against
168 // its user id, not its user name. If necessary, determine the user id
169 // first.
170 //
171 if (im.isPartiallyIdentified() ) {
172 fullyIdentifyCurrentUser();
173 }
174 query = query.forUser(JosmUserIdentityManager.getInstance().getUserId());
175 }
176 if (canceled) return;
177 getProgressMonitor().indeterminateSubTask(tr("Query and download changesets ..."));
178 synchronized(this) {
179 changesetReader= new OsmServerChangesetReader();
180 }
181 downloadedChangesets = new HashSet<Changeset>();
182 downloadedChangesets.addAll(changesetReader.queryChangesets(query, getProgressMonitor().createSubTaskMonitor(0, false)));
183 synchronized (this) {
184 changesetReader = null;
185 }
186 } catch(OsmTransferCanceledException e) {
187 // thrown if user cancel the authentication dialog
188 canceled = true;
189 return;
190 } catch(OsmTransferException e) {
191 if (canceled)
192 return;
193 this.lastException = e;
194 }
195 }
196
197 /* ------------------------------------------------------------------------------- */
198 /* interface ChangesetDownloadTask */
199 /* ------------------------------------------------------------------------------- */
200 public Set<Changeset> getDownloadedChangesets() {
201 return downloadedChangesets;
202 }
203
204 public boolean isCanceled() {
205 return canceled;
206 }
207
208 public boolean isFailed() {
209 return lastException != null;
210 }
211 }