Changeset 10993 in josm
- Timestamp:
- 2016-09-11T12:13:06+02:00 (8 years ago)
- Location:
- trunk/src/org/openstreetmap/josm
- Files:
-
- 1 added
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/data/imagery/WMTSTileSource.java
r10680 r10993 9 9 import java.io.IOException; 10 10 import java.io.InputStream; 11 import java.net.MalformedURLException;12 import java.net.URL;13 11 import java.util.ArrayList; 14 12 import java.util.Collection; … … 31 29 import javax.swing.table.AbstractTableModel; 32 30 import javax.xml.namespace.QName; 33 import javax.xml.stream.XMLInputFactory;34 31 import javax.xml.stream.XMLStreamException; 35 32 import javax.xml.stream.XMLStreamReader; … … 60 57 */ 61 58 public class WMTSTileSource extends AbstractTMSTileSource implements TemplatedTileSource { 59 /** 60 * WMTS namespace address 61 */ 62 public static final String WMTS_NS_URL = "http://www.opengis.net/wmts/1.0"; 63 64 // CHECKSTYLE.OFF: SingleSpaceSeparator 65 private static final QName QN_CONTENTS = new QName(WMTSTileSource.WMTS_NS_URL, "Contents"); 66 private static final QName QN_FORMAT = new QName(WMTSTileSource.WMTS_NS_URL, "Format"); 67 private static final QName QN_LAYER = new QName(WMTSTileSource.WMTS_NS_URL, "Layer"); 68 private static final QName QN_MATRIX_WIDTH = new QName(WMTSTileSource.WMTS_NS_URL, "MatrixWidth"); 69 private static final QName QN_MATRIX_HEIGHT = new QName(WMTSTileSource.WMTS_NS_URL, "MatrixHeight"); 70 private static final QName QN_RESOURCE_URL = new QName(WMTSTileSource.WMTS_NS_URL, "ResourceURL"); 71 private static final QName QN_SCALE_DENOMINATOR = new QName(WMTSTileSource.WMTS_NS_URL, "ScaleDenominator"); 72 private static final QName QN_STYLE = new QName(WMTSTileSource.WMTS_NS_URL, "Style"); 73 private static final QName QN_TILEMATRIX = new QName(WMTSTileSource.WMTS_NS_URL, "TileMatrix"); 74 private static final QName QN_TILEMATRIXSET = new QName(WMTSTileSource.WMTS_NS_URL, "TileMatrixSet"); 75 private static final QName QN_TILEMATRIX_SET_LINK = new QName(WMTSTileSource.WMTS_NS_URL, "TileMatrixSetLink"); 76 private static final QName QN_TILE_WIDTH = new QName(WMTSTileSource.WMTS_NS_URL, "TileWidth"); 77 private static final QName QN_TILE_HEIGHT = new QName(WMTSTileSource.WMTS_NS_URL, "TileHeight"); 78 private static final QName QN_TOPLEFT_CORNER = new QName(WMTSTileSource.WMTS_NS_URL, "TopLeftCorner"); 79 // CHECKSTYLE.ON: SingleSpaceSeparator 80 62 81 private static final String PATTERN_HEADER = "\\{header\\(([^,]+),([^}]+)\\)\\}"; 63 82 … … 68 87 PATTERN_HEADER, 69 88 }; 70 71 private static final String OWS_NS_URL = "http://www.opengis.net/ows/1.1";72 private static final String WMTS_NS_URL = "http://www.opengis.net/wmts/1.0";73 private static final String XLINK_NS_URL = "http://www.w3.org/1999/xlink";74 89 75 90 private static class TileMatrix { … … 139 154 140 155 Layer() { 141 }142 }143 144 private enum TransferMode {145 KVP("KVP"),146 REST("RESTful");147 148 private final String typeString;149 150 TransferMode(String urlString) {151 this.typeString = urlString;152 }153 154 private String getTypeString() {155 return typeString;156 }157 158 private static TransferMode fromString(String s) {159 for (TransferMode type : TransferMode.values()) {160 if (type.getTypeString().equals(s)) {161 return type;162 }163 }164 return null;165 156 } 166 157 } … … 238 229 private TileMatrixSet currentTileMatrixSet; 239 230 private double crsScale; 240 private TransferMode transferMode;231 private GetCapabilitiesParseHelper.TransferMode transferMode; 241 232 242 233 private ScaleList nativeScaleList; … … 250 241 public WMTSTileSource(ImageryInfo info) throws IOException { 251 242 super(info); 252 this.baseUrl = normalizeCapabilitiesUrl(handleTemplate(info.getUrl()));243 this.baseUrl = GetCapabilitiesParseHelper.normalizeCapabilitiesUrl(handleTemplate(info.getUrl())); 253 244 this.layers = getCapabilities(); 254 245 if (this.layers.isEmpty()) … … 291 282 */ 292 283 private Collection<Layer> getCapabilities() throws IOException { 293 XMLInputFactory factory = XMLInputFactory.newFactory();294 // do not try to load external entities, nor validate the XML295 factory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, Boolean.FALSE);296 factory.setProperty(XMLInputFactory.IS_VALIDATING, Boolean.FALSE);297 factory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);298 299 284 try (CachedFile cf = new CachedFile(baseUrl); InputStream in = cf.setHttpHeaders(headers). 300 285 setMaxAge(7 * CachedFile.DAYS). … … 303 288 byte[] data = Utils.readBytesFromStream(in); 304 289 if (data == null || data.length == 0) { 290 cf.clear(); 305 291 throw new IllegalArgumentException("Could not read data from: " + baseUrl); 306 292 } 307 XMLStreamReader reader = factory.createXMLStreamReader(new ByteArrayInputStream(data)); 308 309 Collection<Layer> ret = new ArrayList<>(); 310 for (int event = reader.getEventType(); reader.hasNext(); event = reader.next()) { 311 if (event == XMLStreamReader.START_ELEMENT) { 312 if (new QName(OWS_NS_URL, "OperationsMetadata").equals(reader.getName())) { 313 parseOperationMetadata(reader); 293 294 try { 295 XMLStreamReader reader = GetCapabilitiesParseHelper.getReader(new ByteArrayInputStream(data)); 296 Collection<Layer> ret = new ArrayList<>(); 297 for (int event = reader.getEventType(); reader.hasNext(); event = reader.next()) { 298 if (event == XMLStreamReader.START_ELEMENT) { 299 if (GetCapabilitiesParseHelper.QN_OWS_OPERATIONS_METADATA.equals(reader.getName())) { 300 parseOperationMetadata(reader); 301 } 302 303 if (QN_CONTENTS.equals(reader.getName())) { 304 ret = parseContents(reader); 305 } 314 306 } 315 316 if (new QName(WMTS_NS_URL, "Contents").equals(reader.getName())) { 317 ret = parseContents(reader); 318 } 319 } 320 } 321 return ret; 322 } catch (XMLStreamException e) { 323 throw new IllegalArgumentException(e); 324 } 325 } 326 327 /** 328 * Parse Contents tag. Renturns when reader reaches Contents closing tag 307 } 308 return ret; 309 } catch (XMLStreamException e) { 310 cf.clear(); 311 throw new IllegalArgumentException(e); 312 } 313 } 314 } 315 316 /** 317 * Parse Contents tag. Returns when reader reaches Contents closing tag 329 318 * 330 319 * @param reader StAX reader instance … … 336 325 Collection<Layer> layers = new ArrayList<>(); 337 326 for (int event = reader.getEventType(); 338 reader.hasNext() && !(event == XMLStreamReader.END_ELEMENT && new QName(WMTS_NS_URL, "Contents").equals(reader.getName()));327 reader.hasNext() && !(event == XMLStreamReader.END_ELEMENT && QN_CONTENTS.equals(reader.getName())); 339 328 event = reader.next()) { 340 329 if (event == XMLStreamReader.START_ELEMENT) { 341 if ( new QName(WMTS_NS_URL, "Layer").equals(reader.getName())) {330 if (QN_LAYER.equals(reader.getName())) { 342 331 layers.add(parseLayer(reader)); 343 332 } 344 if ( new QName(WMTS_NS_URL, "TileMatrixSet").equals(reader.getName())) {333 if (QN_TILEMATRIXSET.equals(reader.getName())) { 345 334 TileMatrixSet entry = parseTileMatrixSet(reader); 346 335 matrixSetById.put(entry.identifier, entry); … … 372 361 373 362 for (int event = reader.getEventType(); 374 reader.hasNext() && !(event == XMLStreamReader.END_ELEMENT && new QName(WMTS_NS_URL, "Layer").equals(reader.getName()));363 reader.hasNext() && !(event == XMLStreamReader.END_ELEMENT && QN_LAYER.equals(reader.getName())); 375 364 event = reader.next()) { 376 365 if (event == XMLStreamReader.START_ELEMENT) { 377 366 tagStack.push(reader.getName()); 378 367 if (tagStack.size() == 2) { 379 if ( new QName(WMTS_NS_URL, "Format").equals(reader.getName())) {368 if (QN_FORMAT.equals(reader.getName())) { 380 369 layer.format = reader.getElementText(); 381 } else if ( new QName(OWS_NS_URL, "Identifier").equals(reader.getName())) {370 } else if (GetCapabilitiesParseHelper.QN_OWS_IDENTIFIER.equals(reader.getName())) { 382 371 layer.name = reader.getElementText(); 383 } else if ( new QName(WMTS_NS_URL, "ResourceURL").equals(reader.getName()) &&372 } else if (QN_RESOURCE_URL.equals(reader.getName()) && 384 373 "tile".equals(reader.getAttributeValue("", "resourceType"))) { 385 374 layer.baseUrl = reader.getAttributeValue("", "template"); 386 } else if ( new QName(WMTS_NS_URL, "Style").equals(reader.getName()) &&375 } else if (QN_STYLE.equals(reader.getName()) && 387 376 "true".equals(reader.getAttributeValue("", "isDefault"))) { 388 if ( moveReaderToTag(reader, new QName[] {new QName(OWS_NS_URL, "Identifier")})) {377 if (GetCapabilitiesParseHelper.moveReaderToTag(reader, new QName[] {GetCapabilitiesParseHelper.QN_OWS_IDENTIFIER})) { 389 378 layer.style = reader.getElementText(); 390 379 tagStack.push(reader.getName()); // keep tagStack in sync 391 380 } 392 } else if ( new QName(WMTS_NS_URL, "TileMatrixSetLink").equals(reader.getName())) {381 } else if (QN_TILEMATRIX_SET_LINK.equals(reader.getName())) { 393 382 layer.tileMatrixSetLinks.add(praseTileMatrixSetLink(reader)); 394 383 } else { 395 moveReaderToEndCurrentTag(reader);384 GetCapabilitiesParseHelper.moveReaderToEndCurrentTag(reader); 396 385 } 397 386 } … … 413 402 414 403 /** 415 * Moves the reader to the closing tag of current tag.416 * @param reader XML stream reader positioned on XMLStreamReader.START_ELEMENT417 * @throws XMLStreamException when parse exception occurs418 */419 private static void moveReaderToEndCurrentTag(XMLStreamReader reader) throws XMLStreamException {420 int level = 0;421 QName tag = reader.getName();422 for (int event = reader.getEventType(); reader.hasNext(); event = reader.next()) {423 switch (event) {424 case XMLStreamReader.START_ELEMENT:425 level += 1;426 break;427 case XMLStreamReader.END_ELEMENT:428 level -= 1;429 if (level == 0 && tag.equals(reader.getName())) {430 return;431 }432 }433 if (level < 0) {434 throw new IllegalStateException("WMTS Parser error - moveReaderToEndCurrentTag failed to find closing tag");435 }436 }437 throw new IllegalStateException("WMTS Parser error - moveReaderToEndCurrentTag failed to find closing tag");438 439 }440 441 /**442 404 * Gets TileMatrixSetLink value. Returns when reader is on TileMatrixSetLink closing tag 443 405 * … … 450 412 for (int event = reader.getEventType(); 451 413 reader.hasNext() && !(event == XMLStreamReader.END_ELEMENT && 452 new QName(WMTS_NS_URL, "TileMatrixSetLink").equals(reader.getName()));414 QN_TILEMATRIX_SET_LINK.equals(reader.getName())); 453 415 event = reader.next()) { 454 if (event == XMLStreamReader.START_ELEMENT && new QName(WMTS_NS_URL, "TileMatrixSet").equals(reader.getName())) {416 if (event == XMLStreamReader.START_ELEMENT && QN_TILEMATRIXSET.equals(reader.getName())) { 455 417 ret = reader.getElementText(); 456 418 } … … 468 430 TileMatrixSetBuilder matrixSet = new TileMatrixSetBuilder(); 469 431 for (int event = reader.getEventType(); 470 reader.hasNext() && !(event == XMLStreamReader.END_ELEMENT && new QName(WMTS_NS_URL, "TileMatrixSet").equals(reader.getName()));432 reader.hasNext() && !(event == XMLStreamReader.END_ELEMENT && QN_TILEMATRIXSET.equals(reader.getName())); 471 433 event = reader.next()) { 472 434 if (event == XMLStreamReader.START_ELEMENT) { 473 if ( new QName(OWS_NS_URL, "Identifier").equals(reader.getName())) {435 if (GetCapabilitiesParseHelper.QN_OWS_IDENTIFIER.equals(reader.getName())) { 474 436 matrixSet.identifier = reader.getElementText(); 475 437 } 476 if ( new QName(OWS_NS_URL, "SupportedCRS").equals(reader.getName())) {477 matrixSet.crs = crsToCode(reader.getElementText());478 } 479 if ( new QName(WMTS_NS_URL, "TileMatrix").equals(reader.getName())) {438 if (GetCapabilitiesParseHelper.QN_OWS_SUPPORTED_CRS.equals(reader.getName())) { 439 matrixSet.crs = GetCapabilitiesParseHelper.crsToCode(reader.getElementText()); 440 } 441 if (QN_TILEMATRIX.equals(reader.getName())) { 480 442 matrixSet.tileMatrix.add(parseTileMatrix(reader, matrixSet.crs)); 481 443 } … … 501 463 } 502 464 for (int event = reader.getEventType(); 503 reader.hasNext() && !(event == XMLStreamReader.END_ELEMENT && new QName(WMTS_NS_URL, "TileMatrix").equals(reader.getName()));465 reader.hasNext() && !(event == XMLStreamReader.END_ELEMENT && QN_TILEMATRIX.equals(reader.getName())); 504 466 event = reader.next()) { 505 467 if (event == XMLStreamReader.START_ELEMENT) { 506 if ( new QName(OWS_NS_URL, "Identifier").equals(reader.getName())) {468 if (GetCapabilitiesParseHelper.QN_OWS_IDENTIFIER.equals(reader.getName())) { 507 469 ret.identifier = reader.getElementText(); 508 470 } 509 if ( new QName(WMTS_NS_URL, "ScaleDenominator").equals(reader.getName())) {471 if (QN_SCALE_DENOMINATOR.equals(reader.getName())) { 510 472 ret.scaleDenominator = Double.parseDouble(reader.getElementText()); 511 473 } 512 if ( new QName(WMTS_NS_URL, "TopLeftCorner").equals(reader.getName())) {474 if (QN_TOPLEFT_CORNER.equals(reader.getName())) { 513 475 String[] topLeftCorner = reader.getElementText().split(" "); 514 476 if (matrixProj.switchXY()) { … … 518 480 } 519 481 } 520 if ( new QName(WMTS_NS_URL, "TileHeight").equals(reader.getName())) {482 if (QN_TILE_HEIGHT.equals(reader.getName())) { 521 483 ret.tileHeight = Integer.parseInt(reader.getElementText()); 522 484 } 523 if ( new QName(WMTS_NS_URL, "TileWidth").equals(reader.getName())) {485 if (QN_TILE_WIDTH.equals(reader.getName())) { 524 486 ret.tileWidth = Integer.parseInt(reader.getElementText()); 525 487 } 526 if ( new QName(WMTS_NS_URL, "MatrixHeight").equals(reader.getName())) {488 if (QN_MATRIX_HEIGHT.equals(reader.getName())) { 527 489 ret.matrixHeight = Integer.parseInt(reader.getElementText()); 528 490 } 529 if ( new QName(WMTS_NS_URL, "MatrixWidth").equals(reader.getName())) {491 if (QN_MATRIX_WIDTH.equals(reader.getName())) { 530 492 ret.matrixWidth = Integer.parseInt(reader.getElementText()); 531 493 } … … 549 511 for (int event = reader.getEventType(); 550 512 reader.hasNext() && !(event == XMLStreamReader.END_ELEMENT && 551 new QName(OWS_NS_URL, "OperationsMetadata").equals(reader.getName()));513 GetCapabilitiesParseHelper.QN_OWS_OPERATIONS_METADATA.equals(reader.getName())); 552 514 event = reader.next()) { 553 515 if (event == XMLStreamReader.START_ELEMENT) { 554 if ( new QName(OWS_NS_URL, "Operation").equals(reader.getName()) && "GetTile".equals(reader.getAttributeValue("", "name")) &&555 moveReaderToTag(reader, new QName[]{556 new QName(OWS_NS_URL, "DCP"),557 new QName(OWS_NS_URL, "HTTP"),558 new QName(OWS_NS_URL, "Get"),516 if (GetCapabilitiesParseHelper.QN_OWS_OPERATION.equals(reader.getName()) && "GetTile".equals(reader.getAttributeValue("", "name")) && 517 GetCapabilitiesParseHelper.moveReaderToTag(reader, new QName[]{ 518 GetCapabilitiesParseHelper.QN_OWS_DCP, 519 GetCapabilitiesParseHelper.QN_OWS_HTTP, 520 GetCapabilitiesParseHelper.QN_OWS_GET, 559 521 560 522 })) { 561 this.baseUrl = reader.getAttributeValue(XLINK_NS_URL, "href"); 562 this.transferMode = getTransferMode(reader); 563 } 564 } 565 } 566 } 567 568 /** 569 * Parses Operation[@name='GetTile']/DCP/HTTP/Get section. Returns when reader is on Get closing tag. 570 * @param reader StAX reader instance 571 * @return TransferMode coded in this section 572 * @throws XMLStreamException See {@link XMLStreamReader} 573 */ 574 private static TransferMode getTransferMode(XMLStreamReader reader) throws XMLStreamException { 575 QName getQname = new QName(OWS_NS_URL, "Get"); 576 577 Utils.ensure(getQname.equals(reader.getName()), "WMTS Parser state invalid. Expected element %s, got %s", 578 getQname, reader.getName()); 579 for (int event = reader.getEventType(); 580 reader.hasNext() && !(event == XMLStreamReader.END_ELEMENT && getQname.equals(reader.getName())); 581 event = reader.next()) { 582 if (event == XMLStreamReader.START_ELEMENT && new QName(OWS_NS_URL, "Constraint").equals(reader.getName()) 583 && "GetEncoding".equals(reader.getAttributeValue("", "name"))) { 584 moveReaderToTag(reader, new QName[]{ 585 new QName(OWS_NS_URL, "AllowedValues"), 586 new QName(OWS_NS_URL, "Value") 587 }); 588 return TransferMode.fromString(reader.getElementText()); 589 } 590 } 591 return null; 592 } 593 594 /** 595 * Moves reader to first occurrence of the structure equivalent of Xpath tags[0]/tags[1]../tags[n]. If fails to find 596 * moves the reader to the closing tag of current tag 597 * 598 * @param reader StAX reader instance 599 * @param tags array of tags 600 * @return true if tag was found, false otherwise 601 * @throws XMLStreamException See {@link XMLStreamReader} 602 */ 603 private static boolean moveReaderToTag(XMLStreamReader reader, QName ... tags) throws XMLStreamException { 604 QName stopTag = reader.getName(); 605 int currentLevel = 0; 606 QName searchTag = tags[currentLevel]; 607 QName parentTag = null; 608 QName skipTag = null; 609 610 for (int event = 0; //skip current element, so we will not skip it as a whole 611 reader.hasNext() && !(event == XMLStreamReader.END_ELEMENT && stopTag.equals(reader.getName())); 612 event = reader.next()) { 613 if (event == XMLStreamReader.END_ELEMENT && skipTag != null && skipTag.equals(reader.getName())) { 614 skipTag = null; 615 } 616 if (skipTag == null) { 617 if (event == XMLStreamReader.START_ELEMENT) { 618 if (searchTag.equals(reader.getName())) { 619 currentLevel += 1; 620 if (currentLevel >= tags.length) { 621 return true; // found! 622 } 623 parentTag = searchTag; 624 searchTag = tags[currentLevel]; 625 } else { 626 skipTag = reader.getName(); 627 } 628 } 629 630 if (event == XMLStreamReader.END_ELEMENT && parentTag != null && parentTag.equals(reader.getName())) { 631 currentLevel -= 1; 632 searchTag = parentTag; 633 if (currentLevel >= 0) { 634 parentTag = tags[currentLevel]; 635 } else { 636 parentTag = null; 637 } 638 } 639 } 640 } 641 return false; 642 } 643 644 private static String normalizeCapabilitiesUrl(String url) throws MalformedURLException { 645 URL inUrl = new URL(url); 646 URL ret = new URL(inUrl.getProtocol(), inUrl.getHost(), inUrl.getPort(), inUrl.getFile()); 647 return ret.toExternalForm(); 648 } 649 650 private static String crsToCode(String crsIdentifier) { 651 if (crsIdentifier.startsWith("urn:ogc:def:crs:")) { 652 return crsIdentifier.replaceFirst("urn:ogc:def:crs:([^:]*):.*:(.*)$", "$1:$2"); 653 } 654 return crsIdentifier; 523 this.baseUrl = reader.getAttributeValue(GetCapabilitiesParseHelper.XLINK_NS_URL, "href"); 524 this.transferMode = GetCapabilitiesParseHelper.getTransferMode(reader); 525 } 526 } 527 } 655 528 } 656 529 -
trunk/src/org/openstreetmap/josm/io/CachedFile.java
r10686 r10993 525 525 } 526 526 } 527 528 /** 529 * Clears the cached file 530 * @throws IOException 531 * @since 10993 532 */ 533 public void clear() throws IOException { 534 File f = getFile(); 535 if (f != null && f.exists()) { 536 Utils.deleteFile(f); 537 } 538 } 527 539 }
Note:
See TracChangeset
for help on using the changeset viewer.