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

Last change on this file since 7083 was 7083, checked in by Don-vip, 10 years ago

see #8465 - replace Utils.equal by Objects.equals, new in Java 7

File size: 10.7 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.MirroredInputStream;
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 MirroredInputStream(source)) {
53 InputSource is = new InputSource(UTFInputStreamReader.create(in));
54 factory.newSAXParser().parse(is, parser);
55 return parser.entries;
56 }
57 } catch (SAXException e) {
58 throw e;
59 } catch (ParserConfigurationException e) {
60 Main.error(e); // broken SAXException chaining
61 throw new SAXException(e);
62 }
63 }
64
65 private static class Parser extends DefaultHandler {
66 private StringBuffer accumulator = new StringBuffer();
67
68 private Stack<State> states;
69
70 List<ImageryInfo> entries;
71
72 /**
73 * Skip the current entry because it has mandatory attributes
74 * that this version of JOSM cannot process.
75 */
76 boolean skipEntry;
77
78 ImageryInfo entry;
79 ImageryBounds bounds;
80 Shape shape;
81 List<String> projections;
82
83 @Override public void startDocument() {
84 accumulator = new StringBuffer();
85 skipEntry = false;
86 states = new Stack<>();
87 states.push(State.INIT);
88 entries = new ArrayList<>();
89 entry = null;
90 bounds = null;
91 projections = null;
92 }
93
94 @Override
95 public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
96 accumulator.setLength(0);
97 State newState = null;
98 switch (states.peek()) {
99 case INIT:
100 if ("imagery".equals(qName)) {
101 newState = State.IMAGERY;
102 }
103 break;
104 case IMAGERY:
105 if ("entry".equals(qName)) {
106 entry = new ImageryInfo();
107 skipEntry = false;
108 newState = State.ENTRY;
109 }
110 break;
111 case ENTRY:
112 if (Arrays.asList(new String[] {
113 "name",
114 "type",
115 "default",
116 "url",
117 "eula",
118 "min-zoom",
119 "max-zoom",
120 "attribution-text",
121 "attribution-url",
122 "logo-image",
123 "logo-url",
124 "terms-of-use-text",
125 "terms-of-use-url",
126 "country-code",
127 "icon",
128 }).contains(qName)) {
129 newState = State.ENTRY_ATTRIBUTE;
130 } else if ("bounds".equals(qName)) {
131 try {
132 bounds = new ImageryBounds(
133 atts.getValue("min-lat") + "," +
134 atts.getValue("min-lon") + "," +
135 atts.getValue("max-lat") + "," +
136 atts.getValue("max-lon"), ",");
137 } catch (IllegalArgumentException e) {
138 break;
139 }
140 newState = State.BOUNDS;
141 } else if ("projections".equals(qName)) {
142 projections = new ArrayList<>();
143 newState = State.PROJECTIONS;
144 }
145 break;
146 case BOUNDS:
147 if ("shape".equals(qName)) {
148 shape = new Shape();
149 newState = State.SHAPE;
150 }
151 break;
152 case SHAPE:
153 if ("point".equals(qName)) {
154 try {
155 shape.addPoint(atts.getValue("lat"), atts.getValue("lon"));
156 } catch (IllegalArgumentException e) {
157 break;
158 }
159 }
160 break;
161 case PROJECTIONS:
162 if ("code".equals(qName)) {
163 newState = State.CODE;
164 }
165 break;
166 }
167 /**
168 * Did not recognize the element, so the new state is UNKNOWN.
169 * This includes the case where we are already inside an unknown
170 * element, i.e. we do not try to understand the inner content
171 * of an unknown element, but wait till it's over.
172 */
173 if (newState == null) {
174 newState = State.UNKNOWN;
175 }
176 states.push(newState);
177 if (newState == State.UNKNOWN && "true".equals(atts.getValue("mandatory"))) {
178 skipEntry = true;
179 }
180 return;
181 }
182
183 @Override
184 public void characters(char[] ch, int start, int length) {
185 accumulator.append(ch, start, length);
186 }
187
188 @Override
189 public void endElement(String namespaceURI, String qName, String rqName) {
190 switch (states.pop()) {
191 case INIT:
192 throw new RuntimeException("parsing error: more closing than opening elements");
193 case ENTRY:
194 if ("entry".equals(qName)) {
195 if (!skipEntry) {
196 entries.add(entry);
197 }
198 entry = null;
199 }
200 break;
201 case ENTRY_ATTRIBUTE:
202 switch(qName) {
203 case "name":
204 entry.setTranslatedName(accumulator.toString());
205 break;
206 case "type":
207 boolean found = false;
208 for (ImageryType type : ImageryType.values()) {
209 if (Objects.equals(accumulator.toString(), type.getTypeString())) {
210 entry.setImageryType(type);
211 found = true;
212 break;
213 }
214 }
215 if (!found) {
216 skipEntry = true;
217 }
218 break;
219 case "default":
220 switch (accumulator.toString()) {
221 case "true":
222 entry.setDefaultEntry(true);
223 break;
224 case "false":
225 entry.setDefaultEntry(false);
226 break;
227 default:
228 skipEntry = true;
229 }
230 break;
231 case "url":
232 entry.setUrl(accumulator.toString());
233 break;
234 case "eula":
235 entry.setEulaAcceptanceRequired(accumulator.toString());
236 break;
237 case "min-zoom":
238 case "max-zoom":
239 Integer val = null;
240 try {
241 val = Integer.parseInt(accumulator.toString());
242 } catch(NumberFormatException e) {
243 val = null;
244 }
245 if (val == null) {
246 skipEntry = true;
247 } else {
248 if ("min-zoom".equals(qName)) {
249 entry.setDefaultMinZoom(val);
250 } else {
251 entry.setDefaultMaxZoom(val);
252 }
253 }
254 break;
255 case "attribution-text":
256 entry.setAttributionText(accumulator.toString());
257 break;
258 case "attribution-url":
259 entry.setAttributionLinkURL(accumulator.toString());
260 break;
261 case "logo-image":
262 entry.setAttributionImage(accumulator.toString());
263 break;
264 case "logo-url":
265 entry.setAttributionImageURL(accumulator.toString());
266 break;
267 case "terms-of-use-text":
268 entry.setTermsOfUseText(accumulator.toString());
269 break;
270 case "terms-of-use-url":
271 entry.setTermsOfUseURL(accumulator.toString());
272 break;
273 case "country-code":
274 entry.setCountryCode(accumulator.toString());
275 break;
276 case "icon":
277 entry.setIcon(accumulator.toString());
278 break;
279 }
280 break;
281 case BOUNDS:
282 entry.setBounds(bounds);
283 bounds = null;
284 break;
285 case SHAPE:
286 bounds.addShape(shape);
287 shape = null;
288 break;
289 case CODE:
290 projections.add(accumulator.toString());
291 break;
292 case PROJECTIONS:
293 entry.setServerProjections(projections);
294 projections = null;
295 break;
296 }
297 }
298 }
299}
Note: See TracBrowser for help on using the repository browser.