001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.io; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.awt.Component; 007import java.awt.GraphicsEnvironment; 008import java.io.IOException; 009import java.util.Collections; 010import java.util.List; 011 012import javax.swing.JOptionPane; 013import javax.swing.SwingUtilities; 014 015import org.openstreetmap.josm.Main; 016import org.openstreetmap.josm.data.UserIdentityManager; 017import org.openstreetmap.josm.data.osm.Changeset; 018import org.openstreetmap.josm.data.osm.ChangesetCache; 019import org.openstreetmap.josm.data.osm.UserInfo; 020import org.openstreetmap.josm.gui.ExceptionDialogUtil; 021import org.openstreetmap.josm.gui.PleaseWaitRunnable; 022import org.openstreetmap.josm.gui.util.GuiHelper; 023import org.openstreetmap.josm.io.ChangesetQuery; 024import org.openstreetmap.josm.io.OsmServerChangesetReader; 025import org.openstreetmap.josm.io.OsmServerUserInfoReader; 026import org.openstreetmap.josm.io.OsmTransferException; 027import org.openstreetmap.josm.tools.Logging; 028import org.xml.sax.SAXException; 029 030/** 031 * This is a task for downloading the open changesets of the current user 032 * from the OSM server. 033 */ 034public class DownloadOpenChangesetsTask extends PleaseWaitRunnable { 035 036 private boolean canceled; 037 private OsmServerChangesetReader reader; 038 private List<Changeset> changesets; 039 private Exception lastException; 040 private final Component parent; 041 042 /** 043 * Constructs the task 044 * @param parent is a component to show error messages 045 */ 046 public DownloadOpenChangesetsTask(Component parent) { 047 super(parent, tr("Downloading open changesets ..."), false /* don't ignore exceptions */); 048 this.parent = parent; 049 } 050 051 @Override 052 protected void cancel() { 053 this.canceled = true; 054 synchronized (this) { 055 if (reader != null) { 056 reader.cancel(); 057 } 058 } 059 } 060 061 @Override 062 protected void finish() { 063 if (UserIdentityManager.getInstance().isAnonymous()) { 064 String msg = tr("Could not retrieve the list of your open changesets because<br>" 065 + "JOSM does not know your identity.<br>" 066 + "You have either chosen to work anonymously or you are not entitled<br>" 067 + "to know the identity of the user on whose behalf you are working."); 068 Logging.warn(msg); 069 if (!GraphicsEnvironment.isHeadless()) { 070 JOptionPane.showMessageDialog(GuiHelper.getFrameForComponent(parent), 071 "<html>" + msg + "</html>", tr("Missing user identity"), JOptionPane.ERROR_MESSAGE); 072 } 073 return; 074 } 075 if (canceled) return; 076 if (lastException != null) { 077 ExceptionDialogUtil.explainException(lastException); 078 return; 079 } 080 if (changesets.isEmpty()) { 081 if (!GraphicsEnvironment.isHeadless()) { 082 JOptionPane.showMessageDialog( 083 Main.parent, 084 tr("There are no open changesets"), 085 tr("No open changesets"), 086 JOptionPane.INFORMATION_MESSAGE 087 ); 088 } 089 return; 090 } 091 SwingUtilities.invokeLater(() -> ChangesetCache.getInstance().update(changesets)); 092 } 093 094 /** 095 * Refreshes the user info from the server. This is necessary if we don't know the users id yet. 096 */ 097 protected void refreshUserIdentity() { 098 UserIdentityManager im = UserIdentityManager.getInstance(); 099 try { 100 OsmServerUserInfoReader infoReader = new OsmServerUserInfoReader(); 101 UserInfo info = infoReader.fetchUserInfo(getProgressMonitor().createSubTaskMonitor(1, false)); 102 im.setFullyIdentified(info.getDisplayName(), info); 103 } catch (OsmTransferException e) { 104 // retrieving the user info can fail if the current user is not authorised to 105 // retrieve it, i.e. if he is working with an OAuth Access Token which doesn't 106 // have the respective privileges or if he didn't or he can't authenticate with 107 // a username/password-pair. 108 // 109 // Downgrade your knowlege about its identity if we've assumed that he was fully 110 // identified. Otherwise, if he is anonymous or partially identified, keep our level 111 // of knowlege. 112 // 113 if (im.isFullyIdentified()) { 114 im.setPartiallyIdentified(im.getUserName()); 115 } 116 Logging.log(Logging.LEVEL_WARN, 117 tr("Failed to retrieve user infos for the current JOSM user. Exception was: {0}", e.toString()), e); 118 } 119 } 120 121 @Override 122 protected void realRun() throws SAXException, IOException, OsmTransferException { 123 try { 124 UserIdentityManager im = UserIdentityManager.getInstance(); 125 if (im.isAnonymous()) { 126 refreshUserIdentity(); 127 } else if (im.isFullyIdentified()) { 128 // do nothing 129 } else if (im.isPartiallyIdentified()) { 130 refreshUserIdentity(); 131 } 132 if (canceled) return; 133 synchronized (this) { 134 reader = new OsmServerChangesetReader(); 135 } 136 ChangesetQuery query = new ChangesetQuery().beingOpen(true); 137 if (im.isAnonymous()) 138 // we still don't know anything about the current user. Can't retrieve 139 // its changesets 140 return; 141 else if (im.isFullyIdentified()) { 142 query = query.forUser(im.getUserId()); 143 } else { 144 // we only know the users name, not its id. Nevermind, try to read 145 // its open changesets anyway. 146 // 147 query = query.forUser(im.getUserName()); 148 } 149 changesets = reader.queryChangesets( 150 query, 151 getProgressMonitor().createSubTaskMonitor(1, false /* not internal */) 152 ); 153 } catch (OsmTransferException e) { 154 if (canceled) 155 return; 156 lastException = e; 157 } 158 } 159 160 /** 161 * Determines if this task has been cancelled. 162 * @return {@code true} if this task has been cancelled 163 */ 164 public boolean isCanceled() { 165 return canceled; 166 } 167 168 /** 169 * Returns the changesets. 170 * @return the changesets, or {@code null} 171 * @since 11110 172 */ 173 public final List<Changeset> getChangesets() { 174 return changesets != null ? Collections.unmodifiableList(changesets) : null; 175 } 176}