From 85a4bbe12518f3ac4af698fcfdabcd47acde074e Mon Sep 17 00:00:00 2001 From: Hannes Janetzek Date: Thu, 3 Apr 2014 16:08:39 +0200 Subject: [PATCH] api: UrlTileSource: - add UrlTileSource.getTileUrl(Tile) to create complete url string - add TileUrlFormatter interface to override default formatter - remove unused return from sendRequest() --- .../source/mapnik/MapnikVectorTileSource.java | 46 ++++++------ .../emu/org/oscim/tiling/source/LwHttp.java | 13 +--- .../source/bitmap/BitmapTileSource.java | 3 +- .../tiling/source/JsonTileDataSource.java | 5 +- .../org/oscim/tiling/source/HttpEngine.java | 2 +- vtm/src/org/oscim/tiling/source/LwHttp.java | 55 ++++++++------ .../org/oscim/tiling/source/OkHttpEngine.java | 25 ++----- .../tiling/source/UrlTileDataSource.java | 7 +- .../oscim/tiling/source/UrlTileSource.java | 71 ++++++++++++------- 9 files changed, 121 insertions(+), 106 deletions(-) diff --git a/vtm-extras/src/org/oscim/tiling/source/mapnik/MapnikVectorTileSource.java b/vtm-extras/src/org/oscim/tiling/source/mapnik/MapnikVectorTileSource.java index 60d1ee03..8bd761aa 100644 --- a/vtm-extras/src/org/oscim/tiling/source/mapnik/MapnikVectorTileSource.java +++ b/vtm-extras/src/org/oscim/tiling/source/mapnik/MapnikVectorTileSource.java @@ -25,32 +25,34 @@ public class MapnikVectorTileSource extends UrlTileSource { public MapnikVectorTileSource() { super("http://d1s11ojcu7opje.cloudfront.net/dev/764e0b8d", ""); + setUrlFormatter(new TileUrlFormatter() { + @Override + public String formatTilePath(UrlTileSource tileSource, Tile tile) { + // url formatter for mapbox streets + byte[] hexTable = { + '0', '1', '2', '3', + '4', '5', '6', '7', + '8', '9', 'a', 'b', + 'c', 'd', 'e', 'f' + }; + StringBuilder sb = new StringBuilder(); + sb.append('/'); + sb.append(hexTable[(tile.tileX) % 16]); + sb.append(hexTable[(tile.tileY) % 16]); + sb.append('/'); + sb.append(tile.zoomLevel); + sb.append('/'); + sb.append(tile.tileX); + sb.append('/'); + sb.append(tile.tileY); + + return sb.toString(); + } + }); } @Override public ITileDataSource getDataSource() { return new UrlTileDataSource(this, new TileDecoder(), getHttpEngine()); } - - public String formatTilePath(Tile tile) { - // url formatter for mapbox streets - byte[] hexTable = { - '0', '1', '2', '3', - '4', '5', '6', '7', - '8', '9', 'a', 'b', - 'c', 'd', 'e', 'f' - }; - StringBuilder sb = new StringBuilder(); - sb.append('/'); - sb.append(hexTable[(tile.tileX) % 16]); - sb.append(hexTable[(tile.tileY) % 16]); - sb.append('/'); - sb.append(tile.zoomLevel); - sb.append('/'); - sb.append(tile.tileX); - sb.append('/'); - sb.append(tile.tileY); - - return sb.toString(); - } } diff --git a/vtm-web/src/org/oscim/gdx/emu/org/oscim/tiling/source/LwHttp.java b/vtm-web/src/org/oscim/gdx/emu/org/oscim/tiling/source/LwHttp.java index 1ca98f7c..b25da4b9 100644 --- a/vtm-web/src/org/oscim/gdx/emu/org/oscim/tiling/source/LwHttp.java +++ b/vtm-web/src/org/oscim/gdx/emu/org/oscim/tiling/source/LwHttp.java @@ -17,7 +17,6 @@ package org.oscim.tiling.source; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.net.URL; import org.oscim.core.Tile; import org.oscim.layers.tile.MapTile; @@ -31,15 +30,12 @@ import com.google.gwt.xhr.client.XMLHttpRequest.ResponseType; public class LwHttp implements HttpEngine { //static final Logger log = LoggerFactory.getLogger(LwHttp.class); - private final String mUrlPath; private XMLHttpRequest mHttpRequest; private ReadyStateChangeHandler mResponseHandler; public LwHttp(UrlTileSource tileSource) { mTileSource = tileSource; - URL url = tileSource.getUrl(); - mUrlPath = url.toString(); } static class Buffer extends InputStream { @@ -72,9 +68,9 @@ public class LwHttp implements HttpEngine { private UrlTileSource mTileSource; - public boolean sendRequest(MapTile tile, final UrlTileDataSource dataSource) { + public void sendRequest(MapTile tile, final UrlTileDataSource dataSource) { - String url = mUrlPath + mTileSource.formatTilePath(tile); + String url = mTileSource.getTileUrl(tile); mHttpRequest = XMLHttpRequest.create(); mHttpRequest.open("GET", url); @@ -101,8 +97,6 @@ public class LwHttp implements HttpEngine { mHttpRequest.setOnReadyStateChange(mResponseHandler); mHttpRequest.send(); - - return true; } public static class LwHttpFactory implements HttpEngine.Factory { @@ -130,7 +124,6 @@ public class LwHttp implements HttpEngine { } @Override - public boolean sendRequest(Tile tile) throws IOException { - return false; + public void sendRequest(Tile tile) throws IOException { } } diff --git a/vtm-web/src/org/oscim/gdx/emu/org/oscim/tiling/source/bitmap/BitmapTileSource.java b/vtm-web/src/org/oscim/gdx/emu/org/oscim/tiling/source/bitmap/BitmapTileSource.java index f8af2caf..e543929a 100644 --- a/vtm-web/src/org/oscim/gdx/emu/org/oscim/tiling/source/bitmap/BitmapTileSource.java +++ b/vtm-web/src/org/oscim/gdx/emu/org/oscim/tiling/source/bitmap/BitmapTileSource.java @@ -60,8 +60,7 @@ public class BitmapTileSource extends UrlTileSource { @Override public void query(final MapTile tile, final ITileDataSink sink) { - String url = mTileSource.getUrl() - + BitmapTileSource.this.formatTilePath(tile); + String url = mTileSource.getTileUrl(tile); SafeUri uri = UriUtils.fromTrustedString(url); diff --git a/vtm-web/src/org/oscim/tiling/source/JsonTileDataSource.java b/vtm-web/src/org/oscim/tiling/source/JsonTileDataSource.java index 35511ecc..5d495c34 100644 --- a/vtm-web/src/org/oscim/tiling/source/JsonTileDataSource.java +++ b/vtm-web/src/org/oscim/tiling/source/JsonTileDataSource.java @@ -59,10 +59,7 @@ public class JsonTileDataSource implements ITileDataSource { mSink = sink; try { - String url = mTileSource.getUrl() - + mTileSource.formatTilePath(tile); - - doGet(url); + doGet(mTileSource.getTileUrl(tile)); } catch (Exception e) { e.printStackTrace(); sink.completed(FAILED); diff --git a/vtm/src/org/oscim/tiling/source/HttpEngine.java b/vtm/src/org/oscim/tiling/source/HttpEngine.java index c99429a4..c5e9c715 100644 --- a/vtm/src/org/oscim/tiling/source/HttpEngine.java +++ b/vtm/src/org/oscim/tiling/source/HttpEngine.java @@ -26,7 +26,7 @@ public interface HttpEngine { InputStream read() throws IOException; - boolean sendRequest(Tile tile) throws IOException; + void sendRequest(Tile tile) throws IOException; void close(); diff --git a/vtm/src/org/oscim/tiling/source/LwHttp.java b/vtm/src/org/oscim/tiling/source/LwHttp.java index 4130ab7f..032a0574 100644 --- a/vtm/src/org/oscim/tiling/source/LwHttp.java +++ b/vtm/src/org/oscim/tiling/source/LwHttp.java @@ -53,7 +53,7 @@ public class LwHttp implements HttpEngine { private final String mHost; private final int mPort; - private int mMaxReq = 0; + private int mMaxRequests = 0; private Socket mSocket; private OutputStream mCommandStream; private Buffer mResponseStream; @@ -66,10 +66,13 @@ public class LwHttp implements HttpEngine { private final byte[] REQUEST_GET_START; private final byte[] REQUEST_GET_END; private final byte[] mRequestBuffer; + private final byte[][] mTilePath; + private final UrlTileSource mTileSource; private LwHttp(UrlTileSource tileSource, byte[][] tilePath) { mTilePath = tilePath; + mTileSource = tileSource; URL url = tileSource.getUrl(); int port = url.getPort(); @@ -109,6 +112,7 @@ public class LwHttp implements HttpEngine { // to avoid a copy in PbfDecoder one could manage the buffer // array directly and provide access to it. static class Buffer extends BufferedInputStream { + static final class Buffer extends BufferedInputStream { OutputStream cache; int bytesRead = 0; int bytesWrote; @@ -188,6 +192,7 @@ public class LwHttp implements HttpEngine { if (marked >= 0) bytesRead = marked; + /* TODO could check if the mark is already invalid */ super.reset(); } @@ -323,17 +328,19 @@ public class LwHttp implements HttpEngine { } @Override - public boolean sendRequest(Tile tile) throws IOException { + public void sendRequest(Tile tile) throws IOException { if (mSocket != null) { - if (mMaxReq-- <= 0) + if (--mMaxRequests < 0) close(); else if (System.nanoTime() - mLastRequest > RESPONSE_TIMEOUT) close(); else { try { - if (mResponseStream.available() > 0) + if (mResponseStream.available() > 0) { + log.debug("still bytes available"); close(); + } } catch (IOException e) { log.debug(e.getMessage()); close(); @@ -346,36 +353,32 @@ public class LwHttp implements HttpEngine { lwHttpConnect(); /* TODO parse from header */ - mMaxReq = RESPONSE_EXPECTED_LIVES; + mMaxRequests = RESPONSE_EXPECTED_LIVES; } - byte[] request = mRequestBuffer; int pos = REQUEST_GET_START.length; - - pos = formatTilePath(tile, request, pos); - int len = REQUEST_GET_END.length; - System.arraycopy(REQUEST_GET_END, 0, request, pos, len); + + pos = formatTilePath(tile, mRequestBuffer, pos); + System.arraycopy(REQUEST_GET_END, 0, mRequestBuffer, pos, len); len += pos; if (dbg) - log.debug("request: {}", new String(request, 0, len)); + log.debug("request: {}", new String(mRequestBuffer, 0, len)); try { - mCommandStream.write(request, 0, len); - mCommandStream.flush(); - return true; + writeRequest(mRequestBuffer, len); } catch (IOException e) { log.debug("recreate connection"); close(); - /* might throw IOException */ lwHttpConnect(); - - mCommandStream.write(request, 0, len); - mCommandStream.flush(); + writeRequest(mRequestBuffer, len); } + } - return true; + private void writeRequest(byte[] request, int length) throws IOException { + mCommandStream.write(request, 0, length); + mCommandStream.flush(); } private boolean lwHttpConnect() throws IOException { @@ -500,10 +503,19 @@ public class LwHttp implements HttpEngine { * @return new position */ private int formatTilePath(Tile tile, byte[] buf, int pos) { + if (mTilePath == null) { + String url = mTileSource.getUrlFormatter() + .formatTilePath(mTileSource, tile); + byte[] b = url.getBytes(); + System.arraycopy(b, 0, buf, pos, b.length); + return pos + b.length; + } + for (byte[] b : mTilePath) { if (b.length == 1) { if (b[0] == '/') { buf[pos++] = '/'; + continue; } else if (b[0] == 'X') { pos = writeInt(tile.tileX, pos, buf); continue; @@ -527,13 +539,16 @@ public class LwHttp implements HttpEngine { @Override public HttpEngine create(UrlTileSource tileSource) { + if (tileSource.getUrlFormatter() != UrlTileSource.URL_FORMATTER) + return new LwHttp(tileSource, null); + + /* use optimized formatter replacing the default */ if (mTilePath == null) { String[] path = tileSource.getTilePath(); mTilePath = new byte[path.length][]; for (int i = 0; i < path.length; i++) mTilePath[i] = path[i].getBytes(); } - return new LwHttp(tileSource, mTilePath); } } diff --git a/vtm/src/org/oscim/tiling/source/OkHttpEngine.java b/vtm/src/org/oscim/tiling/source/OkHttpEngine.java index 1e892e96..ac297b85 100644 --- a/vtm/src/org/oscim/tiling/source/OkHttpEngine.java +++ b/vtm/src/org/oscim/tiling/source/OkHttpEngine.java @@ -21,10 +21,10 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; -import java.net.MalformedURLException; import java.net.URL; import org.oscim.core.Tile; +import org.oscim.utils.IOUtils; import com.squareup.okhttp.OkHttpClient; @@ -57,33 +57,20 @@ public class OkHttpEngine implements HttpEngine { return inputStream; } - HttpURLConnection openConnection(Tile tile) throws MalformedURLException { - return mClient.open(new URL(mTileSource.getUrl() + - mTileSource.formatTilePath(tile))); - } - @Override - public boolean sendRequest(Tile tile) throws IOException { + public void sendRequest(Tile tile) throws IOException { if (tile == null) { throw new IllegalArgumentException("Tile cannot be null."); } + URL url = new URL(mTileSource.getTileUrl(tile)); + HttpURLConnection conn = mClient.open(url); - final HttpURLConnection connection = openConnection(tile); - - inputStream = connection.getInputStream(); - - return true; + inputStream = conn.getInputStream(); } @Override public void close() { - if (inputStream != null) { - try { - inputStream.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } + IOUtils.closeQuietly(inputStream); } @Override diff --git a/vtm/src/org/oscim/tiling/source/UrlTileDataSource.java b/vtm/src/org/oscim/tiling/source/UrlTileDataSource.java index 4cf814cf..001d46ee 100644 --- a/vtm/src/org/oscim/tiling/source/UrlTileDataSource.java +++ b/vtm/src/org/oscim/tiling/source/UrlTileDataSource.java @@ -74,10 +74,9 @@ public class UrlTileDataSource implements ITileDataSource { boolean success = false; TileWriter cacheWriter = null; try { - InputStream is; - if (!mConn.sendRequest(tile)) { - log.debug("{} Request failed", tile); - } else if ((is = mConn.read()) == null) { + mConn.sendRequest(tile); + InputStream is = mConn.read(); + if (is == null) { log.debug("{} Network Error", tile); } else { if (mUseCache) { diff --git a/vtm/src/org/oscim/tiling/source/UrlTileSource.java b/vtm/src/org/oscim/tiling/source/UrlTileSource.java index 100cd9a9..6504c676 100644 --- a/vtm/src/org/oscim/tiling/source/UrlTileSource.java +++ b/vtm/src/org/oscim/tiling/source/UrlTileSource.java @@ -26,11 +26,18 @@ import org.oscim.tiling.source.LwHttp.LwHttpFactory; public abstract class UrlTileSource extends TileSource { + public final static TileUrlFormatter URL_FORMATTER = new DefaultTileUrlFormatter(); + private final URL mUrl; private final String[] mTilePath; private HttpEngine.Factory mHttpFactory; private Map mRequestHeaders; + private TileUrlFormatter mTileUrlFormatter = URL_FORMATTER; + + public interface TileUrlFormatter { + public String formatTilePath(UrlTileSource tileSource, Tile tile); + } public UrlTileSource(String url, String tilePath, int zoomMin, int zoomMax) { this(url, tilePath); @@ -72,29 +79,8 @@ public abstract class UrlTileSource extends TileSource { return mUrl; } - public String formatTilePath(Tile tile) { - // TODO only use the actual replacement positions. - - StringBuilder sb = new StringBuilder(); - for (String b : mTilePath) { - if (b.length() == 1) { - switch (b.charAt(0)) { - case 'X': - sb.append(tile.tileX); - continue; - case 'Y': - sb.append(tile.tileY); - continue; - case 'Z': - sb.append(tile.zoomLevel); - continue; - default: - break; - } - } - sb.append(b); - } - return sb.toString(); + public String getTileUrl(Tile tile) { + return mUrl + mTileUrlFormatter.formatTilePath(this, tile); } public void setHttpEngine(HttpEngine.Factory httpFactory) { @@ -113,11 +99,48 @@ public abstract class UrlTileSource extends TileSource { return mTilePath; } + /** + * + */ + public void setUrlFormatter(TileUrlFormatter formatter) { + mTileUrlFormatter = formatter; + } + + public TileUrlFormatter getUrlFormatter() { + return mTileUrlFormatter; + } + public HttpEngine getHttpEngine() { if (mHttpFactory == null) { mHttpFactory = new LwHttpFactory(); } - return mHttpFactory.create(this); } + + static class DefaultTileUrlFormatter implements TileUrlFormatter { + @Override + public String formatTilePath(UrlTileSource tileSource, Tile tile) { + + StringBuilder sb = new StringBuilder(); + for (String b : tileSource.getTilePath()) { + if (b.length() == 1) { + switch (b.charAt(0)) { + case 'X': + sb.append(tile.tileX); + continue; + case 'Y': + sb.append(tile.tileY); + continue; + case 'Z': + sb.append(tile.zoomLevel); + continue; + default: + break; + } + } + sb.append(b); + } + return sb.toString(); + } + } }