source: josm/trunk/src/org/openstreetmap/josm/data/imagery/GetCapabilitiesParseHelper.java@ 13828

Last change on this file since 13828 was 13828, checked in by wiktorn, 6 years ago

Sonar fixes, javadocs.

See: #16249

File size: 10.9 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.imagery;
3
4import java.io.InputStream;
5import java.net.MalformedURLException;
6import java.net.URL;
7import java.util.Locale;
8import java.util.function.BiFunction;
9
10import javax.xml.namespace.QName;
11import javax.xml.stream.XMLInputFactory;
12import javax.xml.stream.XMLStreamException;
13import javax.xml.stream.XMLStreamReader;
14
15import org.openstreetmap.josm.tools.Utils;
16
17/**
18 * Helper class for handling OGC GetCapabilities documents
19 * @since 10993
20 */
21public final class GetCapabilitiesParseHelper {
22 enum TransferMode {
23 KVP("KVP"),
24 REST("RESTful");
25
26 private final String typeString;
27
28 TransferMode(String urlString) {
29 this.typeString = urlString;
30 }
31
32 private String getTypeString() {
33 return typeString;
34 }
35
36 static TransferMode fromString(String s) {
37 for (TransferMode type : TransferMode.values()) {
38 if (type.getTypeString().equals(s)) {
39 return type;
40 }
41 }
42 return null;
43 }
44 }
45
46 /**
47 * OWS namespace address
48 */
49 public static final String OWS_NS_URL = "http://www.opengis.net/ows/1.1";
50 /**
51 * XML xlink namespace address
52 */
53 public static final String XLINK_NS_URL = "http://www.w3.org/1999/xlink";
54
55 /**
56 * QNames in OWS namespace
57 */
58 // CHECKSTYLE.OFF: SingleSpaceSeparator
59 static final QName QN_OWS_ALLOWED_VALUES = new QName(OWS_NS_URL, "AllowedValues");
60 static final QName QN_OWS_CONSTRAINT = new QName(OWS_NS_URL, "Constraint");
61 static final QName QN_OWS_DCP = new QName(OWS_NS_URL, "DCP");
62 static final QName QN_OWS_GET = new QName(OWS_NS_URL, "Get");
63 static final QName QN_OWS_HTTP = new QName(OWS_NS_URL, "HTTP");
64 static final QName QN_OWS_IDENTIFIER = new QName(OWS_NS_URL, "Identifier");
65 static final QName QN_OWS_OPERATION = new QName(OWS_NS_URL, "Operation");
66 static final QName QN_OWS_OPERATIONS_METADATA = new QName(OWS_NS_URL, "OperationsMetadata");
67 static final QName QN_OWS_SUPPORTED_CRS = new QName(OWS_NS_URL, "SupportedCRS");
68 static final QName QN_OWS_TITLE = new QName(OWS_NS_URL, "Title");
69 static final QName QN_OWS_VALUE = new QName(OWS_NS_URL, "Value");
70 // CHECKSTYLE.ON: SingleSpaceSeparator
71
72 private GetCapabilitiesParseHelper() {
73 // Hide default constructor for utilities classes
74 }
75
76 /**
77 * Returns reader with properties set for parsing WM(T)S documents
78 *
79 * @param in InputStream with pointing to GetCapabilities XML stream
80 * @return safe XMLStreamReader, that is not validating external entities, nor loads DTD's
81 * @throws XMLStreamException if any XML stream error occurs
82 */
83 public static XMLStreamReader getReader(InputStream in) throws XMLStreamException {
84 XMLInputFactory factory = XMLInputFactory.newInstance();
85 // do not try to load external entities, nor validate the XML
86 factory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, Boolean.FALSE);
87 factory.setProperty(XMLInputFactory.IS_VALIDATING, Boolean.FALSE);
88 factory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
89 return factory.createXMLStreamReader(in);
90 }
91
92 /**
93 * Moves the reader to the closing tag of current tag.
94 * @param reader XMLStreamReader which should be moved
95 * @throws XMLStreamException when parse exception occurs
96 */
97 public static void moveReaderToEndCurrentTag(XMLStreamReader reader) throws XMLStreamException {
98 int level = 0;
99 QName tag = reader.getName();
100 for (int event = reader.getEventType(); reader.hasNext(); event = reader.next()) {
101 if (XMLStreamReader.START_ELEMENT == event) {
102 level += 1;
103 } else if (XMLStreamReader.END_ELEMENT == event) {
104 level -= 1;
105 if (level == 0 && tag.equals(reader.getName())) {
106 return;
107 }
108 }
109 if (level < 0) {
110 throw new IllegalStateException("WMTS Parser error - moveReaderToEndCurrentTag failed to find closing tag");
111 }
112 }
113 throw new IllegalStateException("WMTS Parser error - moveReaderToEndCurrentTag failed to find closing tag");
114 }
115
116 /**
117 * Returns whole content of the element that reader is pointing at, including other XML elements within (with their tags).
118 *
119 * @param reader XMLStreamReader that should point to start of element
120 * @return content of current tag
121 * @throws XMLStreamException if any XML stream error occurs
122 */
123 public static String getElementTextWithSubtags(XMLStreamReader reader) throws XMLStreamException {
124 StringBuilder ret = new StringBuilder();
125 int level = 0;
126 QName tag = reader.getName();
127 for (int event = reader.getEventType(); reader.hasNext(); event = reader.next()) {
128 if (XMLStreamReader.START_ELEMENT == event) {
129 if (level > 0) {
130 ret.append('<').append(reader.getLocalName()).append('>');
131 }
132 level += 1;
133 } else if (XMLStreamReader.END_ELEMENT == event) {
134 level -= 1;
135 if (level == 0 && tag.equals(reader.getName())) {
136 return ret.toString();
137 }
138 ret.append("</").append(reader.getLocalName()).append('>');
139 } else if (XMLStreamReader.CHARACTERS == event) {
140 ret.append(reader.getText());
141 }
142 if (level < 0) {
143 throw new IllegalStateException("WMTS Parser error - moveReaderToEndCurrentTag failed to find closing tag");
144 }
145 }
146 throw new IllegalStateException("WMTS Parser error - moveReaderToEndCurrentTag failed to find closing tag");
147 }
148
149
150 /**
151 * Moves reader to first occurrence of the structure equivalent of Xpath tags[0]/tags[1]../tags[n]. If fails to find
152 * moves the reader to the closing tag of current tag
153 *
154 * @param tags array of tags
155 * @param reader XMLStreamReader which should be moved
156 * @return true if tag was found, false otherwise
157 * @throws XMLStreamException See {@link XMLStreamReader}
158 */
159 public static boolean moveReaderToTag(XMLStreamReader reader, QName... tags) throws XMLStreamException {
160 return moveReaderToTag(reader, QName::equals, tags);
161 }
162
163 /**
164 * Moves reader to first occurrence of the structure equivalent of Xpath tags[0]/tags[1]../tags[n]. If fails to find
165 * moves the reader to the closing tag of current tag
166 *
167 * @param tags array of tags
168 * @param reader XMLStreamReader which should be moved
169 * @param equalsFunc function to check equality of the tags
170 * @return true if tag was found, false otherwise
171 * @throws XMLStreamException See {@link XMLStreamReader}
172 */
173 public static boolean moveReaderToTag(XMLStreamReader reader,
174 BiFunction<QName, QName, Boolean> equalsFunc, QName... tags) throws XMLStreamException {
175 QName stopTag = reader.getName();
176 int currentLevel = 0;
177 QName searchTag = tags[currentLevel];
178 QName parentTag = null;
179 QName skipTag = null;
180
181 for (int event = 0; //skip current element, so we will not skip it as a whole
182 reader.hasNext() && !(event == XMLStreamReader.END_ELEMENT && equalsFunc.apply(stopTag, reader.getName()));
183 event = reader.next()) {
184 if (event == XMLStreamReader.END_ELEMENT && skipTag != null && equalsFunc.apply(skipTag, reader.getName())) {
185 skipTag = null;
186 }
187 if (skipTag == null) {
188 if (event == XMLStreamReader.START_ELEMENT) {
189 if (equalsFunc.apply(searchTag, reader.getName())) {
190 currentLevel += 1;
191 if (currentLevel >= tags.length) {
192 return true; // found!
193 }
194 parentTag = searchTag;
195 searchTag = tags[currentLevel];
196 } else {
197 skipTag = reader.getName();
198 }
199 }
200
201 if (event == XMLStreamReader.END_ELEMENT && parentTag != null && equalsFunc.apply(parentTag, reader.getName())) {
202 currentLevel -= 1;
203 searchTag = parentTag;
204 if (currentLevel >= 0) {
205 parentTag = tags[currentLevel];
206 } else {
207 parentTag = null;
208 }
209 }
210 }
211 }
212 return false;
213 }
214
215 /**
216 * Parses Operation[@name='GetTile']/DCP/HTTP/Get section. Returns when reader is on Get closing tag.
217 * @param reader StAX reader instance
218 * @return TransferMode coded in this section
219 * @throws XMLStreamException See {@link XMLStreamReader}
220 */
221 public static TransferMode getTransferMode(XMLStreamReader reader) throws XMLStreamException {
222 QName getQname = QN_OWS_GET;
223
224 Utils.ensure(getQname.equals(reader.getName()), "WMTS Parser state invalid. Expected element %s, got %s",
225 getQname, reader.getName());
226 for (int event = reader.getEventType();
227 reader.hasNext() && !(event == XMLStreamReader.END_ELEMENT && getQname.equals(reader.getName()));
228 event = reader.next()) {
229 if (event == XMLStreamReader.START_ELEMENT && QN_OWS_CONSTRAINT.equals(reader.getName())
230 && "GetEncoding".equals(reader.getAttributeValue("", "name"))) {
231 moveReaderToTag(reader, QN_OWS_ALLOWED_VALUES, QN_OWS_VALUE);
232 return TransferMode.fromString(reader.getElementText());
233 }
234 }
235 return null;
236 }
237
238 /**
239 * Normalize url
240 *
241 * @param url URL
242 * @return normalized URL
243 * @throws MalformedURLException in case of malformed URL
244 * @since 10993
245 */
246 public static String normalizeCapabilitiesUrl(String url) throws MalformedURLException {
247 URL inUrl = new URL(url);
248 URL ret = new URL(inUrl.getProtocol(), inUrl.getHost(), inUrl.getPort(), inUrl.getFile());
249 return ret.toExternalForm();
250 }
251
252 /**
253 * Convert CRS identifier to plain code
254 * @param crsIdentifier CRS identifier
255 * @return CRS Identifier as it is used within JOSM (without prefix)
256 * @see <a href="https://portal.opengeospatial.org/files/?artifact_id=24045">
257 * Definition identifier URNs in OGC namespace, chapter 7.2: URNs for single objects</a>
258 */
259 public static String crsToCode(String crsIdentifier) {
260 if (crsIdentifier.startsWith("urn:ogc:def:crs:")) {
261 return crsIdentifier.replaceFirst("urn:ogc:def:crs:([^:]*)(?::.*)?:(.*)$", "$1:$2").toUpperCase(Locale.ENGLISH);
262 }
263 return crsIdentifier;
264 }
265}
Note: See TracBrowser for help on using the repository browser.