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.ArrayList;
007import java.util.Collections;
008import java.util.HashMap;
009import java.util.List;
010import java.util.Map;
011
012import org.openstreetmap.josm.Main;
013
014/**
015 * Represents the server capabilities
016 *
017 * Example capabilites document:
018 *
019 * <osm version="0.6" generator="OpenStreetMap server">
020 *   <api>
021 *     <version minimum="0.6" maximum="0.6"/>
022 *     <area maximum="0.25"/>
023 *     <tracepoints per_page="5000"/>
024 *     <waynodes maximum="2000"/>
025 *     <changesets maximum_elements="50000"/>
026 *     <timeout seconds="300"/>
027 *   </api>
028 *   <policy>
029 *     <imagery>
030 *       <blacklist regex=".*\.google\.com/.*"/>
031 *       <blacklist regex=".*209\.85\.2\d\d.*"/>
032 *       <blacklist regex=".*209\.85\.1[3-9]\d.*"/>
033 *       <blacklist regex=".*209\.85\.12[89].*"/>
034 *     </imagery>
035 *   </policy>
036 * </osm>
037 *
038 * This class is used in conjunction with a very primitive parser
039 * and simply stuffs the each tag and its attributes into a hash
040 * of hashes, with the exception of the "blacklist" tag which gets
041 * a list of its own. The DOM hierarchy is disregarded.
042 */
043public class Capabilities {
044
045    private Map<String, HashMap<String,String>> capabilities;
046    private List<String> imageryBlacklist;
047
048    /**
049     * Constructs new {@code Capabilities}.
050     */
051    public Capabilities() {
052        clear();
053    }
054
055    public boolean isDefined(String element, String attribute) {
056        if (! capabilities.containsKey(element)) return false;
057        HashMap<String, String> e = capabilities.get(element);
058        if (e == null) return false;
059        return (e.get(attribute) != null);
060    }
061
062    public String get(String element, String attribute ) {
063        if (! capabilities.containsKey(element)) return null;
064        HashMap<String, String> e = capabilities.get(element);
065        if (e == null) return null;
066        return e.get(attribute);
067    }
068
069    /**
070     * returns the value of configuration item in the capabilities as
071     * double value
072     *
073     * @param element  the name of the element
074     * @param attribute the name of the attribute
075     * @return the value; null, if the respective configuration item doesn't exist
076     * @throws NumberFormatException  if the value is not a valid double
077     */
078    public Double getDouble(String element, String attribute) throws NumberFormatException {
079        String s = get(element, attribute);
080        if (s == null) return null;
081        return Double.parseDouble(s);
082    }
083
084    public Long getLong(String element, String attribute) {
085        String s = get(element, attribute);
086        if (s == null) return null;
087        return Long.parseLong(s);
088    }
089
090    public void put(String element, String attribute, String value) {
091        if (element.equals("blacklist")) {
092            if (attribute.equals("regex")) {
093                imageryBlacklist.add(value);
094            }
095        } else {
096            if (! capabilities.containsKey(element))  {
097                HashMap<String,String> h = new HashMap<String, String>();
098                capabilities.put(element, h);
099            }
100            HashMap<String, String> e = capabilities.get(element);
101            e.put(attribute, value);
102        }
103    }
104
105    public void clear() {
106        capabilities = new HashMap<String, HashMap<String,String>>();
107        imageryBlacklist = new ArrayList<String>();
108    }
109
110    public boolean supportsVersion(String version) {
111        return get("version", "minimum").compareTo(version) <= 0
112        && get("version", "maximum").compareTo(version) >= 0;
113    }
114
115    /**
116     * Returns the max number of objects in a changeset. -1 if either the capabilities
117     * don't include this parameter or if the parameter value is illegal (not a number,
118     * a negative number)
119     *
120     * @return the max number of objects in a changeset
121     */
122    public int getMaxChangesetSize() {
123        String v = get("changesets", "maximum_elements");
124        if (v == null) return -1;
125        try {
126            int n = Integer.parseInt(v);
127            if (n <= 0) {
128                Main.warn(tr("Illegal value of attribute ''{0}'' of element ''{1}'' in server capabilities. Got ''{2}''", "changesets", "maximum_elements", n ));
129                return -1;
130            }
131            return n;
132        } catch (NumberFormatException e) {
133            Main.warn(tr("Illegal value of attribute ''{0}'' of element ''{1}'' in server capabilities. Got ''{2}''", "changesets", "maximum_elements", v ));
134            return -1;
135        }
136    }
137
138    /**
139     * checks if the given URL is blacklisted by one of the of the
140     * regular expressions.
141     */
142
143    public boolean isOnImageryBlacklist(String url)
144    {
145        if (url != null && imageryBlacklist != null) {
146            for (String blacklistRegex : imageryBlacklist) {
147                if (url.matches(blacklistRegex))
148                    return true;
149            }
150        }
151        return false;
152    }
153
154    /**
155     * returns the full list of blacklist regular expressions.
156     */
157    public List<String> getImageryBlacklist()
158    {
159        return Collections.unmodifiableList(imageryBlacklist);
160    }
161}