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