// License: GPL. For details, see Readme.txt file. package org.openstreetmap.gui.jmapviewer.tilesources; import java.util.HashMap; import java.util.Map; import java.util.Random; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.openstreetmap.gui.jmapviewer.interfaces.TemplatedTileSource; /** * Handles templated TMS Tile Source. Templated means, that some patterns within * URL gets substituted. * * Supported parameters * {zoom} - substituted with zoom level * {z} - as above * {NUMBER-zoom} - substituted with result of equation "NUMBER - zoom", * eg. {20-zoom} for zoom level 15 will result in 5 in this place * {zoom+number} - substituted with result of equation "zoom + number", * eg. {zoom+5} for zoom level 15 will result in 20. * {x} - substituted with X tile number * {y} - substituted with Y tile number * {!y} - substituted with Yahoo Y tile number * {-y} - substituted with reversed Y tile number * {switch:VAL_A,VAL_B,VAL_C,...} - substituted with one of VAL_A, VAL_B, VAL_C. Usually * used to specify many tile servers * {header:(HEADER_NAME,HEADER_VALUE)} - sets the headers to be sent to tile server */ public class TemplatedTMSTileSource extends TMSTileSource implements TemplatedTileSource { private Random rand; private String[] randomParts; private final Map<String, String> headers = new HashMap<>(); // CHECKSTYLE.OFF: SingleSpaceSeparator private static final String COOKIE_HEADER = "Cookie"; private static final String PATTERN_ZOOM = "\\{(?:(\\d+)-)?z(?:oom)?([+-]\\d+)?\\}"; private static final String PATTERN_X = "\\{x\\}"; private static final String PATTERN_Y = "\\{y\\}"; private static final String PATTERN_Y_YAHOO = "\\{!y\\}"; private static final String PATTERN_NEG_Y = "\\{-y\\}"; private static final String PATTERN_SWITCH = "\\{switch:([^}]+)\\}"; private static final String PATTERN_HEADER = "\\{header\\(([^,]+),([^}]+)\\)\\}"; // CHECKSTYLE.ON: SingleSpaceSeparator private static final String[] ALL_PATTERNS = { PATTERN_HEADER, PATTERN_ZOOM, PATTERN_X, PATTERN_Y, PATTERN_Y_YAHOO, PATTERN_NEG_Y, PATTERN_SWITCH }; /** * Creates Templated TMS Tile Source based on ImageryInfo * @param info imagery info */ public TemplatedTMSTileSource(TileSourceInfo info) { super(info); if (info.getCookies() != null) { headers.put(COOKIE_HEADER, info.getCookies()); } handleTemplate(); } private void handleTemplate() { // Capturing group pattern on switch values Matcher m = Pattern.compile(".*"+PATTERN_SWITCH+".*").matcher(baseUrl); if (m.matches()) { rand = new Random(); randomParts = m.group(1).split(","); } Pattern pattern = Pattern.compile(PATTERN_HEADER); StringBuffer output = new StringBuffer(); Matcher matcher = pattern.matcher(baseUrl); while (matcher.find()) { headers.put(matcher.group(1), matcher.group(2)); matcher.appendReplacement(output, ""); } matcher.appendTail(output); baseUrl = output.toString(); } @Override public Map<String, String> getHeaders() { return headers; } @Override public String getTileUrl(int zoom, int tilex, int tiley) { int finalZoom = zoom; Matcher m = Pattern.compile(".*"+PATTERN_ZOOM+".*").matcher(this.baseUrl); if (m.matches()) { if (m.group(1) != null) { finalZoom = Integer.parseInt(m.group(1))-zoom; } if (m.group(2) != null) { String ofs = m.group(2); if (ofs.startsWith("+")) ofs = ofs.substring(1); finalZoom += Integer.parseInt(ofs); } } String r = this.baseUrl .replaceAll(PATTERN_ZOOM, Integer.toString(finalZoom)) .replaceAll(PATTERN_X, Integer.toString(tilex)) .replaceAll(PATTERN_Y, Integer.toString(tiley)) .replaceAll(PATTERN_Y_YAHOO, Integer.toString((int) Math.pow(2, zoom-1)-1-tiley)) .replaceAll(PATTERN_NEG_Y, Integer.toString((int) Math.pow(2, zoom)-1-tiley)); if (rand != null) { r = r.replaceAll(PATTERN_SWITCH, randomParts[rand.nextInt(randomParts.length)]); } return r; } /** * Checks if url is acceptable by this Tile Source * @param url URL to check */ public static void checkUrl(String url) { assert url != null && !"".equals(url) : "URL cannot be null or empty"; Matcher m = Pattern.compile("\\{[^}]*\\}").matcher(url); while (m.find()) { boolean isSupportedPattern = false; for (String pattern : ALL_PATTERNS) { if (m.group().matches(pattern)) { isSupportedPattern = true; break; } } if (!isSupportedPattern) { throw new IllegalArgumentException( m.group() + " is not a valid TMS argument. Please check this server URL:\n" + url); } } } }