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.DateUtils;
021import org.w3c.dom.Document;
022import org.w3c.dom.Node;
023import org.w3c.dom.NodeList;
024
025public class OsmServerUserInfoReader extends OsmServerReader {
026
027    static protected String getAttribute(Node node, String name) {
028        return node.getAttributes().getNamedItem(name).getNodeValue();
029    }
030
031    /**
032     * Parses the given XML data and returns the associated user info.
033     * @param document The XML contents
034     * @return The user info
035     * @throws OsmDataParsingException if parsing goes wrong
036     */
037    static public UserInfo buildFromXML(Document document) throws OsmDataParsingException {
038        try {
039            XPathFactory factory = XPathFactory.newInstance();
040            XPath xpath = factory.newXPath();
041            UserInfo userInfo = new UserInfo();
042            Node xmlNode = (Node)xpath.compile("/osm/user[1]").evaluate(document, XPathConstants.NODE);
043            if ( xmlNode== null)
044                throw new OsmDataParsingException(tr("XML tag <user> is missing."));
045
046            // -- id
047            String v = getAttribute(xmlNode, "id");
048            if (v == null)
049                throw new OsmDataParsingException(tr("Missing attribute ''{0}'' on XML tag ''{1}''.", "id", "user"));
050            try {
051                userInfo.setId(Integer.parseInt(v));
052            } catch(NumberFormatException e) {
053                throw new OsmDataParsingException(tr("Illegal value for attribute ''{0}'' on XML tag ''{1}''. Got {2}.", "id", "user", v));
054            }
055            // -- display name
056            v = getAttribute(xmlNode, "display_name");
057            userInfo.setDisplayName(v);
058            // -- account_created
059            v = getAttribute(xmlNode, "account_created");
060            if (v!=null) {
061                userInfo.setAccountCreated(DateUtils.fromString(v));
062            }
063            // -- description
064            xmlNode = (Node)xpath.compile("/osm/user[1]/description[1]/text()").evaluate(document, XPathConstants.NODE);
065            if (xmlNode != null) {
066                userInfo.setDescription(xmlNode.getNodeValue());
067            }
068            // -- home
069            xmlNode = (Node)xpath.compile("/osm/user[1]/home").evaluate(document, XPathConstants.NODE);
070            if (xmlNode != null) {
071                v = getAttribute(xmlNode, "lat");
072                if (v == null)
073                    throw new OsmDataParsingException(tr("Missing attribute ''{0}'' on XML tag ''{1}''.", "lat", "home"));
074                double lat;
075                try {
076                    lat = Double.parseDouble(v);
077                } catch(NumberFormatException e) {
078                    throw new OsmDataParsingException(tr("Illegal value for attribute ''{0}'' on XML tag ''{1}''. Got {2}.", "lat", "home", v));
079                }
080
081                v = getAttribute(xmlNode, "lon");
082                if (v == null)
083                    throw new OsmDataParsingException(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 OsmDataParsingException(tr("Illegal value for attribute ''{0}'' on XML tag ''{1}''. Got {2}.", "lon", "home", v));
089                }
090
091                v = getAttribute(xmlNode, "zoom");
092                if (v == null)
093                    throw new OsmDataParsingException(tr("Missing attribute ''{0}'' on XML tag ''{1}''.", "zoom", "home"));
094                int zoom;
095                try {
096                    zoom = Integer.parseInt(v);
097                } catch(NumberFormatException e) {
098                    throw new OsmDataParsingException(tr("Illegal value for attribute ''{0}'' on XML tag ''{1}''. Got {2}.", "zoom", "home", v));
099                }
100                userInfo.setHome(new LatLon(lat,lon));
101                userInfo.setHomeZoom(zoom);
102            }
103
104            // -- language list
105            NodeList xmlNodeList = (NodeList)xpath.compile("/osm/user[1]/languages[1]/lang/text()").evaluate(document, XPathConstants.NODESET);
106            if (xmlNodeList != null) {
107                List<String> languages = new LinkedList<String>();
108                for (int i=0; i < xmlNodeList.getLength(); i++) {
109                    languages.add(xmlNodeList.item(i).getNodeValue());
110                }
111                userInfo.setLanguages(languages);
112            }
113            
114            // -- messages
115            xmlNode = (Node)xpath.compile("/osm/user[1]/messages/received").evaluate(document, XPathConstants.NODE);
116            if (xmlNode != null) {
117                v = getAttribute(xmlNode, "unread");
118                if (v == null)
119                    throw new OsmDataParsingException(tr("Missing attribute ''{0}'' on XML tag ''{1}''.", "unread", "received"));
120                try {
121                    userInfo.setUnreadMessages(Integer.parseInt(v));
122                } catch(NumberFormatException e) {
123                    throw new OsmDataParsingException(tr("Illegal value for attribute ''{0}'' on XML tag ''{1}''. Got {2}.", "unread", "received", v), e);
124                }
125            }
126            
127            return userInfo;
128        } catch(XPathException e) {
129            throw new OsmDataParsingException(e);
130        }
131    }
132
133    /**
134     * Constructs a new {@code OsmServerUserInfoReader}.
135     */
136    public OsmServerUserInfoReader() {
137        setDoAuthenticate(true);
138    }
139
140    @Override
141    public DataSet parseOsm(ProgressMonitor progressMonitor) throws OsmTransferException {
142        // not implemented
143        return null;
144    }
145
146    public UserInfo fetchUserInfo(ProgressMonitor monitor) throws OsmTransferException {
147        try {
148            monitor.beginTask("");
149            monitor.indeterminateSubTask(tr("Reading user info ..."));
150            InputStream in = getInputStream("user/details", monitor.createSubTaskMonitor(1, true));
151            return buildFromXML(
152                    DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(in)
153            );
154        } catch(OsmTransferException e) {
155            throw e;
156        } catch(Exception e) {
157            throw new OsmTransferException(e);
158        } finally {
159            monitor.finishTask();
160        }
161    }
162}