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.InputStream; 007import java.util.LinkedList; 008import java.util.List; 009 010import javax.xml.parsers.DocumentBuilderFactory; 011import javax.xml.xpath.XPath; 012import javax.xml.xpath.XPathConstants; 013import javax.xml.xpath.XPathException; 014import javax.xml.xpath.XPathFactory; 015 016import org.openstreetmap.josm.data.coor.LatLon; 017import org.openstreetmap.josm.data.osm.DataSet; 018import org.openstreetmap.josm.data.osm.UserInfo; 019import org.openstreetmap.josm.gui.progress.ProgressMonitor; 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 026public class OsmServerUserInfoReader extends OsmServerReader { 027 028 protected static String getAttribute(Node node, String name) { 029 return node.getAttributes().getNamedItem(name).getNodeValue(); 030 } 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 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 try { 171 monitor.beginTask(""); 172 monitor.indeterminateSubTask(tr("Reading user info ...")); 173 try (InputStream in = getInputStream("user/details", monitor.createSubTaskMonitor(1, true), reason)) { 174 return buildFromXML( 175 DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(in) 176 ); 177 } 178 } catch (OsmTransferException e) { 179 throw e; 180 } catch (Exception e) { 181 throw new OsmTransferException(e); 182 } finally { 183 monitor.finishTask(); 184 } 185 } 186}