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}