001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.io; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.time.DateTimeException; 007import java.util.LinkedList; 008import java.util.List; 009 010import javax.xml.xpath.XPath; 011import javax.xml.xpath.XPathConstants; 012import javax.xml.xpath.XPathException; 013import javax.xml.xpath.XPathFactory; 014 015import org.openstreetmap.josm.data.coor.LatLon; 016import org.openstreetmap.josm.data.osm.DataSet; 017import org.openstreetmap.josm.data.osm.UserInfo; 018import org.openstreetmap.josm.gui.progress.ProgressMonitor; 019import org.openstreetmap.josm.tools.UncheckedParseException; 020import org.openstreetmap.josm.tools.XmlParsingException; 021import org.openstreetmap.josm.tools.date.DateUtils; 022import org.w3c.dom.Document; 023import org.w3c.dom.Node; 024import org.w3c.dom.NodeList; 025 026/** 027 * Download and parse info of the logged in user (OSM API v0.6 "/user/details"). 028 * @see <a href="https://wiki.openstreetmap.org/wiki/API_v0.6#Details_of_the_logged-in_user">/user/details</a> 029 */ 030public class OsmServerUserInfoReader extends OsmServerReader { 031 032 /** 033 * Parses the given XML data and returns the associated user info. 034 * @param document The XML contents 035 * @return The user info 036 * @throws XmlParsingException if parsing goes wrong 037 */ 038 public static UserInfo buildFromXML(Document document) throws XmlParsingException { 039 try { 040 XPathFactory factory = XPathFactory.newInstance(); 041 XPath xpath = factory.newXPath(); 042 UserInfo userInfo = new UserInfo(); 043 Node xmlNode = (Node) xpath.compile("/osm/user[1]").evaluate(document, XPathConstants.NODE); 044 if (xmlNode == null) 045 throw new XmlParsingException(tr("XML tag <user> is missing.")); 046 047 // -- id 048 String v = getAttribute(xmlNode, "id"); 049 if (v == null) 050 throw new XmlParsingException(tr("Missing attribute ''{0}'' on XML tag ''{1}''.", "id", "user")); 051 try { 052 userInfo.setId(Integer.parseInt(v)); 053 } catch (NumberFormatException e) { 054 throw new XmlParsingException(tr("Illegal value for attribute ''{0}'' on XML tag ''{1}''. Got {2}.", "id", "user", v), e); 055 } 056 // -- display name 057 v = getAttribute(xmlNode, "display_name"); 058 userInfo.setDisplayName(v); 059 // -- account_created 060 v = getAttribute(xmlNode, "account_created"); 061 if (v != null) { 062 userInfo.setAccountCreated(DateUtils.fromString(v)); 063 } 064 // -- description 065 xmlNode = (Node) xpath.compile("/osm/user[1]/description[1]/text()").evaluate(document, XPathConstants.NODE); 066 if (xmlNode != null) { 067 userInfo.setDescription(xmlNode.getNodeValue()); 068 } 069 // -- home 070 xmlNode = (Node) xpath.compile("/osm/user[1]/home").evaluate(document, XPathConstants.NODE); 071 if (xmlNode != null) { 072 v = getAttribute(xmlNode, "lat"); 073 if (v == null) 074 throw new XmlParsingException(tr("Missing attribute ''{0}'' on XML tag ''{1}''.", "lat", "home")); 075 double lat; 076 try { 077 lat = Double.parseDouble(v); 078 } catch (NumberFormatException e) { 079 throw new XmlParsingException(tr("Illegal value for attribute ''{0}'' on XML tag ''{1}''. Got {2}.", 080 "lat", "home", v), e); 081 } 082 083 v = getAttribute(xmlNode, "lon"); 084 if (v == null) 085 throw new XmlParsingException(tr("Missing attribute ''{0}'' on XML tag ''{1}''.", "lon", "home")); 086 double lon; 087 try { 088 lon = Double.parseDouble(v); 089 } catch (NumberFormatException e) { 090 throw new XmlParsingException(tr("Illegal value for attribute ''{0}'' on XML tag ''{1}''. Got {2}.", 091 "lon", "home", v), e); 092 } 093 094 v = getAttribute(xmlNode, "zoom"); 095 if (v == null) 096 throw new XmlParsingException(tr("Missing attribute ''{0}'' on XML tag ''{1}''.", "zoom", "home")); 097 int zoom; 098 try { 099 zoom = Integer.parseInt(v); 100 } catch (NumberFormatException e) { 101 throw new XmlParsingException(tr("Illegal value for attribute ''{0}'' on XML tag ''{1}''. Got {2}.", 102 "zoom", "home", v), e); 103 } 104 userInfo.setHome(new LatLon(lat, lon)); 105 userInfo.setHomeZoom(zoom); 106 } 107 108 // -- language list 109 NodeList xmlNodeList = (NodeList) xpath.compile("/osm/user[1]/languages[1]/lang/text()").evaluate(document, XPathConstants.NODESET); 110 if (xmlNodeList != null) { 111 List<String> languages = new LinkedList<>(); 112 for (int i = 0; i < xmlNodeList.getLength(); i++) { 113 languages.add(xmlNodeList.item(i).getNodeValue()); 114 } 115 userInfo.setLanguages(languages); 116 } 117 118 // -- messages 119 xmlNode = (Node) xpath.compile("/osm/user[1]/messages/received").evaluate(document, XPathConstants.NODE); 120 if (xmlNode != null) { 121 v = getAttribute(xmlNode, "unread"); 122 if (v == null) 123 throw new XmlParsingException(tr("Missing attribute ''{0}'' on XML tag ''{1}''.", "unread", "received")); 124 try { 125 userInfo.setUnreadMessages(Integer.parseInt(v)); 126 } catch (NumberFormatException e) { 127 throw new XmlParsingException( 128 tr("Illegal value for attribute ''{0}'' on XML tag ''{1}''. Got {2}.", "unread", "received", v), e); 129 } 130 } 131 132 return userInfo; 133 } catch (XPathException | UncheckedParseException | DateTimeException e) { 134 throw new XmlParsingException(e); 135 } 136 } 137 138 /** 139 * Constructs a new {@code OsmServerUserInfoReader}. 140 */ 141 public OsmServerUserInfoReader() { 142 setDoAuthenticate(true); 143 } 144 145 @Override 146 public DataSet parseOsm(ProgressMonitor progressMonitor) throws OsmTransferException { 147 // not implemented 148 return null; 149 } 150 151 /** 152 * Fetches user info, without explicit reason. 153 * @param monitor The progress monitor 154 * @return The user info 155 * @throws OsmTransferException if something goes wrong 156 */ 157 public UserInfo fetchUserInfo(ProgressMonitor monitor) throws OsmTransferException { 158 return fetchUserInfo(monitor, null); 159 } 160 161 /** 162 * Fetches user info, with an explicit reason. 163 * @param monitor The progress monitor 164 * @param reason The reason to show on console. Can be {@code null} if no reason is given 165 * @return The user info 166 * @throws OsmTransferException if something goes wrong 167 * @since 6695 168 */ 169 public UserInfo fetchUserInfo(ProgressMonitor monitor, String reason) throws OsmTransferException { 170 return fetchData("user/details", tr("Reading user info ..."), 171 OsmServerUserInfoReader::buildFromXML, monitor, reason); 172 } 173}