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