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