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 }