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)); 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}.", "lat", "home", v)); 080 } 081 082 v = getAttribute(xmlNode, "lon"); 083 if (v == null) 084 throw new XmlParsingException(tr("Missing attribute ''{0}'' on XML tag ''{1}''.", "lon", "home")); 085 double lon; 086 try { 087 lon = Double.parseDouble(v); 088 } catch(NumberFormatException e) { 089 throw new XmlParsingException(tr("Illegal value for attribute ''{0}'' on XML tag ''{1}''. Got {2}.", "lon", "home", v)); 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}.", "zoom", "home", v)); 100 } 101 userInfo.setHome(new LatLon(lat,lon)); 102 userInfo.setHomeZoom(zoom); 103 } 104 105 // -- language list 106 NodeList xmlNodeList = (NodeList)xpath.compile("/osm/user[1]/languages[1]/lang/text()").evaluate(document, XPathConstants.NODESET); 107 if (xmlNodeList != null) { 108 List<String> languages = new LinkedList<>(); 109 for (int i=0; i < xmlNodeList.getLength(); i++) { 110 languages.add(xmlNodeList.item(i).getNodeValue()); 111 } 112 userInfo.setLanguages(languages); 113 } 114 115 // -- messages 116 xmlNode = (Node)xpath.compile("/osm/user[1]/messages/received").evaluate(document, XPathConstants.NODE); 117 if (xmlNode != null) { 118 v = getAttribute(xmlNode, "unread"); 119 if (v == null) 120 throw new XmlParsingException(tr("Missing attribute ''{0}'' on XML tag ''{1}''.", "unread", "received")); 121 try { 122 userInfo.setUnreadMessages(Integer.parseInt(v)); 123 } catch(NumberFormatException e) { 124 throw new XmlParsingException(tr("Illegal value for attribute ''{0}'' on XML tag ''{1}''. Got {2}.", "unread", "received", v), e); 125 } 126 } 127 128 return userInfo; 129 } catch(XPathException e) { 130 throw new XmlParsingException(e); 131 } 132 } 133 134 /** 135 * Constructs a new {@code OsmServerUserInfoReader}. 136 */ 137 public OsmServerUserInfoReader() { 138 setDoAuthenticate(true); 139 } 140 141 @Override 142 public DataSet parseOsm(ProgressMonitor progressMonitor) throws OsmTransferException { 143 // not implemented 144 return null; 145 } 146 147 /** 148 * Fetches user info, without explicit reason. 149 * @param monitor The progress monitor 150 * @return The user info 151 * @throws OsmTransferException if something goes wrong 152 */ 153 public UserInfo fetchUserInfo(ProgressMonitor monitor) throws OsmTransferException { 154 return fetchUserInfo(monitor, null); 155 } 156 157 /** 158 * Fetches user info, with an explicit reason. 159 * @param monitor The progress monitor 160 * @param reason The reason to show on console. Can be {@code null} if no reason is given 161 * @return The user info 162 * @throws OsmTransferException if something goes wrong 163 * @since 6695 164 */ 165 public UserInfo fetchUserInfo(ProgressMonitor monitor, String reason) throws OsmTransferException { 166 try { 167 monitor.beginTask(""); 168 monitor.indeterminateSubTask(tr("Reading user info ...")); 169 try (InputStream in = getInputStream("user/details", monitor.createSubTaskMonitor(1, true), reason)) { 170 return buildFromXML( 171 DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(in) 172 ); 173 } 174 } catch(OsmTransferException e) { 175 throw e; 176 } catch(Exception e) { 177 throw new OsmTransferException(e); 178 } finally { 179 monitor.finishTask(); 180 } 181 } 182}