1 | // License: GPL. For details, see LICENSE file.
|
---|
2 | package org.openstreetmap.josm.io;
|
---|
3 |
|
---|
4 | import static org.openstreetmap.josm.tools.I18n.tr;
|
---|
5 |
|
---|
6 | import java.io.IOException;
|
---|
7 | import java.util.ArrayList;
|
---|
8 | import java.util.Collections;
|
---|
9 | import java.util.HashMap;
|
---|
10 | import java.util.List;
|
---|
11 | import java.util.Map;
|
---|
12 |
|
---|
13 | import javax.xml.parsers.ParserConfigurationException;
|
---|
14 |
|
---|
15 | import org.openstreetmap.josm.tools.Logging;
|
---|
16 | import org.openstreetmap.josm.tools.XmlUtils;
|
---|
17 | import org.xml.sax.Attributes;
|
---|
18 | import org.xml.sax.InputSource;
|
---|
19 | import org.xml.sax.SAXException;
|
---|
20 | import org.xml.sax.helpers.DefaultHandler;
|
---|
21 |
|
---|
22 | /**
|
---|
23 | * Represents the OSM API server capabilities.
|
---|
24 | *
|
---|
25 | * Example capabilities document:
|
---|
26 | * <pre>
|
---|
27 | * <osm version="0.6" generator="OpenStreetMap server">
|
---|
28 | * <api>
|
---|
29 | * <version minimum="0.6" maximum="0.6"/>
|
---|
30 | * <area maximum="0.25"/>
|
---|
31 | * <tracepoints per_page="5000"/>
|
---|
32 | * <waynodes maximum="2000"/>
|
---|
33 | * <changesets maximum_elements="10000"/>
|
---|
34 | * <timeout seconds="300"/>
|
---|
35 | * <status database="online" api="online" gpx="online"/>
|
---|
36 | * </api>
|
---|
37 | * <policy>
|
---|
38 | * <imagery>
|
---|
39 | * <blacklist regex=".*\.google\.com/.*"/>
|
---|
40 | * <blacklist regex=".*209\.85\.2\d\d.*"/>
|
---|
41 | * <blacklist regex=".*209\.85\.1[3-9]\d.*"/>
|
---|
42 | * <blacklist regex=".*209\.85\.12[89].*"/>
|
---|
43 | * </imagery>
|
---|
44 | * </policy>
|
---|
45 | * </osm>
|
---|
46 | * </pre>
|
---|
47 | * This class is used in conjunction with a very primitive parser
|
---|
48 | * and simply stuffs the each tag and its attributes into a hash
|
---|
49 | * of hashes, with the exception of the "blacklist" tag which gets
|
---|
50 | * a list of its own. The DOM hierarchy is disregarded.
|
---|
51 | */
|
---|
52 | public class Capabilities {
|
---|
53 |
|
---|
54 | private final Map<String, Map<String, String>> capabilities;
|
---|
55 | private final List<String> imageryBlacklist;
|
---|
56 |
|
---|
57 | /**
|
---|
58 | * Constructs new {@code Capabilities}.
|
---|
59 | */
|
---|
60 | public Capabilities() {
|
---|
61 | capabilities = new HashMap<>();
|
---|
62 | imageryBlacklist = new ArrayList<>();
|
---|
63 | }
|
---|
64 |
|
---|
65 | /**
|
---|
66 | * Determines if given element and attribute are defined.
|
---|
67 | *
|
---|
68 | * @param element the name of the element
|
---|
69 | * @param attribute the name of the attribute
|
---|
70 | * @return {@code true} if defined, {@code false} otherwise
|
---|
71 | */
|
---|
72 | public boolean isDefined(String element, String attribute) {
|
---|
73 | if (!capabilities.containsKey(element)) return false;
|
---|
74 | Map<String, String> e = capabilities.get(element);
|
---|
75 | if (e == null) return false;
|
---|
76 | return e.get(attribute) != null;
|
---|
77 | }
|
---|
78 |
|
---|
79 | /**
|
---|
80 | * Returns the value of configuration item in the capabilities as string value.
|
---|
81 | *
|
---|
82 | * @param element the name of the element
|
---|
83 | * @param attribute the name of the attribute
|
---|
84 | * @return the value; {@code null}, if the respective configuration item does not exist
|
---|
85 | */
|
---|
86 | public String get(String element, String attribute) {
|
---|
87 | if (!capabilities.containsKey(element)) return null;
|
---|
88 | Map<String, String> e = capabilities.get(element);
|
---|
89 | if (e == null) return null;
|
---|
90 | return e.get(attribute);
|
---|
91 | }
|
---|
92 |
|
---|
93 | /**
|
---|
94 | * Returns the value of configuration item in the capabilities as double value.
|
---|
95 | *
|
---|
96 | * @param element the name of the element
|
---|
97 | * @param attribute the name of the attribute
|
---|
98 | * @return the value; {@code null}, if the respective configuration item does not exist
|
---|
99 | * @throws NumberFormatException if the value is not a valid double
|
---|
100 | */
|
---|
101 | public Double getDouble(String element, String attribute) {
|
---|
102 | String s = get(element, attribute);
|
---|
103 | if (s == null) return null;
|
---|
104 | return Double.valueOf(s);
|
---|
105 | }
|
---|
106 |
|
---|
107 | /**
|
---|
108 | * Returns the value of configuration item in the capabilities as long value.
|
---|
109 | *
|
---|
110 | * @param element the name of the element
|
---|
111 | * @param attribute the name of the attribute
|
---|
112 | * @return the value; {@code null}, if the respective configuration item does not exist
|
---|
113 | * @throws NumberFormatException if the value is not a valid long
|
---|
114 | */
|
---|
115 | public Long getLong(String element, String attribute) {
|
---|
116 | String s = get(element, attribute);
|
---|
117 | if (s == null) return null;
|
---|
118 | return Long.valueOf(s);
|
---|
119 | }
|
---|
120 |
|
---|
121 | /**
|
---|
122 | * Adds a new configuration item.
|
---|
123 | *
|
---|
124 | * @param element the name of the element
|
---|
125 | * @param attribute the name of the attribute
|
---|
126 | * @param value the value as string
|
---|
127 | */
|
---|
128 | public void put(String element, String attribute, String value) {
|
---|
129 | if ("blacklist".equals(element)) {
|
---|
130 | if ("regex".equals(attribute)) {
|
---|
131 | imageryBlacklist.add(value);
|
---|
132 | }
|
---|
133 | } else {
|
---|
134 | if (!capabilities.containsKey(element)) {
|
---|
135 | capabilities.put(element, new HashMap<>());
|
---|
136 | }
|
---|
137 | capabilities.get(element).put(attribute, value);
|
---|
138 | }
|
---|
139 | }
|
---|
140 |
|
---|
141 | /**
|
---|
142 | * Clears the API capabilities.
|
---|
143 | */
|
---|
144 | public final void clear() {
|
---|
145 | capabilities.clear();
|
---|
146 | imageryBlacklist.clear();
|
---|
147 | }
|
---|
148 |
|
---|
149 | /**
|
---|
150 | * Determines if a given API version is supported.
|
---|
151 | * @param version The API version to check
|
---|
152 | * @return {@code true} is version is between the minimum supported version and the maximum one, {@code false} otherwise
|
---|
153 | */
|
---|
154 | public boolean supportsVersion(String version) {
|
---|
155 | String min = get("version", "minimum");
|
---|
156 | String max = get("version", "maximum");
|
---|
157 | return min != null && max != null
|
---|
158 | && min.compareTo(version) <= 0
|
---|
159 | && max.compareTo(version) >= 0;
|
---|
160 | }
|
---|
161 |
|
---|
162 | private static void warnIllegalValue(String attr, String elem, Object val) {
|
---|
163 | Logging.warn(tr("Illegal value of attribute ''{0}'' of element ''{1}'' in server capabilities. Got ''{2}''", attr, elem, val));
|
---|
164 | }
|
---|
165 |
|
---|
166 | /**
|
---|
167 | * Returns the max number of objects in a changeset. -1 if either the capabilities
|
---|
168 | * don't include this parameter or if the parameter value is illegal (not a number,
|
---|
169 | * a negative number)
|
---|
170 | *
|
---|
171 | * @return the max number of objects in a changeset
|
---|
172 | */
|
---|
173 | public int getMaxChangesetSize() {
|
---|
174 | String v = get("changesets", "maximum_elements");
|
---|
175 | if (v != null) {
|
---|
176 | try {
|
---|
177 | int n = Integer.parseInt(v);
|
---|
178 | if (n <= 0) {
|
---|
179 | warnIllegalValue("changesets", "maximum_elements", n);
|
---|
180 | } else {
|
---|
181 | return n;
|
---|
182 | }
|
---|
183 | } catch (NumberFormatException e) {
|
---|
184 | warnIllegalValue("changesets", "maximum_elements", v);
|
---|
185 | }
|
---|
186 | }
|
---|
187 | return -1;
|
---|
188 | }
|
---|
189 |
|
---|
190 | /**
|
---|
191 | * Returns the max number of nodes in a way. -1 if either the capabilities
|
---|
192 | * don't include this parameter or if the parameter value is illegal (not a number,
|
---|
193 | * a negative number)
|
---|
194 | *
|
---|
195 | * @return the max number of nodes in a way
|
---|
196 | */
|
---|
197 | public long getMaxWayNodes() {
|
---|
198 | String v = get("waynodes", "maximum");
|
---|
199 | if (v != null) {
|
---|
200 | try {
|
---|
201 | long n = Long.parseLong(v);
|
---|
202 | if (n <= 0) {
|
---|
203 | warnIllegalValue("waynodes", "maximum", n);
|
---|
204 | } else {
|
---|
205 | return n;
|
---|
206 | }
|
---|
207 | } catch (NumberFormatException e) {
|
---|
208 | warnIllegalValue("waynodes", "maximum", v);
|
---|
209 | }
|
---|
210 | }
|
---|
211 | return -1;
|
---|
212 | }
|
---|
213 |
|
---|
214 | /**
|
---|
215 | * Checks if the given URL is blacklisted by one of the of the regular expressions.
|
---|
216 | * @param url Imagery URL to check
|
---|
217 | * @return {@code true} if URL is blacklisted, {@code false} otherwise
|
---|
218 | */
|
---|
219 | public boolean isOnImageryBlacklist(String url) {
|
---|
220 | return url != null && imageryBlacklist.stream().anyMatch(url::matches);
|
---|
221 | }
|
---|
222 |
|
---|
223 | /**
|
---|
224 | * Returns the full list of imagery blacklist regular expressions.
|
---|
225 | * @return full list of imagery blacklist regular expressions
|
---|
226 | */
|
---|
227 | public List<String> getImageryBlacklist() {
|
---|
228 | return Collections.unmodifiableList(imageryBlacklist);
|
---|
229 | }
|
---|
230 |
|
---|
231 | /**
|
---|
232 | * A parser for the "capabilities" response XML.
|
---|
233 | * @since 7473
|
---|
234 | */
|
---|
235 | public static final class CapabilitiesParser extends DefaultHandler {
|
---|
236 |
|
---|
237 | private Capabilities capabilities;
|
---|
238 |
|
---|
239 | @Override
|
---|
240 | public void startDocument() {
|
---|
241 | capabilities = new Capabilities();
|
---|
242 | }
|
---|
243 |
|
---|
244 | @Override
|
---|
245 | public void startElement(String namespaceURI, String localName, String qName, Attributes atts) {
|
---|
246 | for (int i = 0; i < atts.getLength(); i++) {
|
---|
247 | capabilities.put(qName, atts.getQName(i), atts.getValue(i));
|
---|
248 | }
|
---|
249 | }
|
---|
250 |
|
---|
251 | /**
|
---|
252 | * Returns the read capabilities.
|
---|
253 | * @return the read capabilities
|
---|
254 | */
|
---|
255 | public Capabilities getCapabilities() {
|
---|
256 | return capabilities;
|
---|
257 | }
|
---|
258 |
|
---|
259 | /**
|
---|
260 | * Parses and returns capabilities from the given input source.
|
---|
261 | *
|
---|
262 | * @param inputSource The input source to read capabilities from
|
---|
263 | * @return the capabilities
|
---|
264 | * @throws SAXException if any SAX errors occur during processing
|
---|
265 | * @throws IOException if any I/O errors occur
|
---|
266 | * @throws ParserConfigurationException if a parser cannot be created
|
---|
267 | */
|
---|
268 | public static Capabilities parse(InputSource inputSource) throws SAXException, IOException, ParserConfigurationException {
|
---|
269 | CapabilitiesParser parser = new CapabilitiesParser();
|
---|
270 | XmlUtils.parseSafeSAX(inputSource, parser);
|
---|
271 | return parser.getCapabilities();
|
---|
272 | }
|
---|
273 | }
|
---|
274 | }
|
---|