source: josm/trunk/src/org/openstreetmap/josm/io/imagery/ImageryReader.java@ 7937

Last change on this file since 7937 was 7937, checked in by bastiK, 9 years ago

add subversion property svn:eol=native

  • Property svn:eol-style set to native
File size: 11.0 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.io.imagery;
3
4import java.io.IOException;
5import java.io.InputStream;
6import java.util.ArrayList;
7import java.util.Arrays;
8import java.util.List;
9import java.util.Objects;
10import java.util.Stack;
11
12import javax.xml.parsers.ParserConfigurationException;
13import javax.xml.parsers.SAXParserFactory;
14
15import org.openstreetmap.josm.Main;
16import org.openstreetmap.josm.data.imagery.ImageryInfo;
17import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryBounds;
18import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
19import org.openstreetmap.josm.data.imagery.Shape;
20import org.openstreetmap.josm.io.CachedFile;
21import org.openstreetmap.josm.io.UTFInputStreamReader;
22import org.xml.sax.Attributes;
23import org.xml.sax.InputSource;
24import org.xml.sax.SAXException;
25import org.xml.sax.helpers.DefaultHandler;
26
27public class ImageryReader {
28
29 private String source;
30
31 private enum State {
32 INIT, // initial state, should always be at the bottom of the stack
33 IMAGERY, // inside the imagery element
34 ENTRY, // inside an entry
35 ENTRY_ATTRIBUTE, // note we are inside an entry attribute to collect the character data
36 PROJECTIONS,
37 CODE,
38 BOUNDS,
39 SHAPE,
40 UNKNOWN, // element is not recognized in the current context
41 }
42
43 public ImageryReader(String source) {
44 this.source = source;
45 }
46
47 public List<ImageryInfo> parse() throws SAXException, IOException {
48 Parser parser = new Parser();
49 try {
50 SAXParserFactory factory = SAXParserFactory.newInstance();
51 factory.setNamespaceAware(true);
52 try (InputStream in = new CachedFile(source)
53 .setMaxAge(1*CachedFile.DAYS)
54 .setCachingStrategy(CachedFile.CachingStrategy.IfModifiedSince)
55 .getInputStream()) {
56 InputSource is = new InputSource(UTFInputStreamReader.create(in));
57 factory.newSAXParser().parse(is, parser);
58 return parser.entries;
59 }
60 } catch (SAXException e) {
61 throw e;
62 } catch (ParserConfigurationException e) {
63 Main.error(e); // broken SAXException chaining
64 throw new SAXException(e);
65 }
66 }
67
68 private static class Parser extends DefaultHandler {
69 private StringBuffer accumulator = new StringBuffer();
70
71 private Stack<State> states;
72
73 List<ImageryInfo> entries;
74
75 /**
76 * Skip the current entry because it has mandatory attributes
77 * that this version of JOSM cannot process.
78 */
79 boolean skipEntry;
80
81 ImageryInfo entry;
82 ImageryBounds bounds;
83 Shape shape;
84 List<String> projections;
85
86 @Override public void startDocument() {
87 accumulator = new StringBuffer();
88 skipEntry = false;
89 states = new Stack<>();
90 states.push(State.INIT);
91 entries = new ArrayList<>();
92 entry = null;
93 bounds = null;
94 projections = null;
95 }
96
97 @Override
98 public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
99 accumulator.setLength(0);
100 State newState = null;
101 switch (states.peek()) {
102 case INIT:
103 if ("imagery".equals(qName)) {
104 newState = State.IMAGERY;
105 }
106 break;
107 case IMAGERY:
108 if ("entry".equals(qName)) {
109 entry = new ImageryInfo();
110 skipEntry = false;
111 newState = State.ENTRY;
112 }
113 break;
114 case ENTRY:
115 if (Arrays.asList(new String[] {
116 "name",
117 "id",
118 "type",
119 "default",
120 "url",
121 "eula",
122 "min-zoom",
123 "max-zoom",
124 "attribution-text",
125 "attribution-url",
126 "logo-image",
127 "logo-url",
128 "terms-of-use-text",
129 "terms-of-use-url",
130 "country-code",
131 "icon",
132 }).contains(qName)) {
133 newState = State.ENTRY_ATTRIBUTE;
134 } else if ("bounds".equals(qName)) {
135 try {
136 bounds = new ImageryBounds(
137 atts.getValue("min-lat") + "," +
138 atts.getValue("min-lon") + "," +
139 atts.getValue("max-lat") + "," +
140 atts.getValue("max-lon"), ",");
141 } catch (IllegalArgumentException e) {
142 break;
143 }
144 newState = State.BOUNDS;
145 } else if ("projections".equals(qName)) {
146 projections = new ArrayList<>();
147 newState = State.PROJECTIONS;
148 }
149 break;
150 case BOUNDS:
151 if ("shape".equals(qName)) {
152 shape = new Shape();
153 newState = State.SHAPE;
154 }
155 break;
156 case SHAPE:
157 if ("point".equals(qName)) {
158 try {
159 shape.addPoint(atts.getValue("lat"), atts.getValue("lon"));
160 } catch (IllegalArgumentException e) {
161 break;
162 }
163 }
164 break;
165 case PROJECTIONS:
166 if ("code".equals(qName)) {
167 newState = State.CODE;
168 }
169 break;
170 }
171 /**
172 * Did not recognize the element, so the new state is UNKNOWN.
173 * This includes the case where we are already inside an unknown
174 * element, i.e. we do not try to understand the inner content
175 * of an unknown element, but wait till it's over.
176 */
177 if (newState == null) {
178 newState = State.UNKNOWN;
179 }
180 states.push(newState);
181 if (newState == State.UNKNOWN && "true".equals(atts.getValue("mandatory"))) {
182 skipEntry = true;
183 }
184 return;
185 }
186
187 @Override
188 public void characters(char[] ch, int start, int length) {
189 accumulator.append(ch, start, length);
190 }
191
192 @Override
193 public void endElement(String namespaceURI, String qName, String rqName) {
194 switch (states.pop()) {
195 case INIT:
196 throw new RuntimeException("parsing error: more closing than opening elements");
197 case ENTRY:
198 if ("entry".equals(qName)) {
199 if (!skipEntry) {
200 entries.add(entry);
201 }
202 entry = null;
203 }
204 break;
205 case ENTRY_ATTRIBUTE:
206 switch(qName) {
207 case "name":
208 entry.setTranslatedName(accumulator.toString());
209 break;
210 case "id":
211 entry.setId(accumulator.toString());
212 break;
213 case "type":
214 boolean found = false;
215 for (ImageryType type : ImageryType.values()) {
216 if (Objects.equals(accumulator.toString(), type.getTypeString())) {
217 entry.setImageryType(type);
218 found = true;
219 break;
220 }
221 }
222 if (!found) {
223 skipEntry = true;
224 }
225 break;
226 case "default":
227 switch (accumulator.toString()) {
228 case "true":
229 entry.setDefaultEntry(true);
230 break;
231 case "false":
232 entry.setDefaultEntry(false);
233 break;
234 default:
235 skipEntry = true;
236 }
237 break;
238 case "url":
239 entry.setUrl(accumulator.toString());
240 break;
241 case "eula":
242 entry.setEulaAcceptanceRequired(accumulator.toString());
243 break;
244 case "min-zoom":
245 case "max-zoom":
246 Integer val = null;
247 try {
248 val = Integer.parseInt(accumulator.toString());
249 } catch(NumberFormatException e) {
250 val = null;
251 }
252 if (val == null) {
253 skipEntry = true;
254 } else {
255 if ("min-zoom".equals(qName)) {
256 entry.setDefaultMinZoom(val);
257 } else {
258 entry.setDefaultMaxZoom(val);
259 }
260 }
261 break;
262 case "attribution-text":
263 entry.setAttributionText(accumulator.toString());
264 break;
265 case "attribution-url":
266 entry.setAttributionLinkURL(accumulator.toString());
267 break;
268 case "logo-image":
269 entry.setAttributionImage(accumulator.toString());
270 break;
271 case "logo-url":
272 entry.setAttributionImageURL(accumulator.toString());
273 break;
274 case "terms-of-use-text":
275 entry.setTermsOfUseText(accumulator.toString());
276 break;
277 case "terms-of-use-url":
278 entry.setTermsOfUseURL(accumulator.toString());
279 break;
280 case "country-code":
281 entry.setCountryCode(accumulator.toString());
282 break;
283 case "icon":
284 entry.setIcon(accumulator.toString());
285 break;
286 }
287 break;
288 case BOUNDS:
289 entry.setBounds(bounds);
290 bounds = null;
291 break;
292 case SHAPE:
293 bounds.addShape(shape);
294 shape = null;
295 break;
296 case CODE:
297 projections.add(accumulator.toString());
298 break;
299 case PROJECTIONS:
300 entry.setServerProjections(projections);
301 projections = null;
302 break;
303 }
304 }
305 }
306}
Note: See TracBrowser for help on using the repository browser.