api changes: UrlTileSource
- move option to override getTileUrl() to UrlTileSource - remove requirement to provide expected mime-type - only need to use setExtension() when using the default url formatter.
This commit is contained in:
parent
cb629744ec
commit
9f626e3716
@ -18,46 +18,21 @@ import org.slf4j.LoggerFactory;
|
||||
public abstract class BitmapTileSource extends UrlTileSource {
|
||||
static final Logger log = LoggerFactory.getLogger(LwHttp.class);
|
||||
|
||||
private final String mFileExtension;
|
||||
private final String mMimeType;
|
||||
|
||||
public BitmapTileSource(String url) {
|
||||
this(url, 0, 17);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create BitmapTileSource for 'url'
|
||||
*
|
||||
* By default path will be formatted as: url/z/x/y.png
|
||||
* Use e.g. setExtension(".jpg") to overide ending or
|
||||
* implement getUrlString() for custom formatting.
|
||||
*/
|
||||
public BitmapTileSource(String url, int zoomMin, int zoomMax) {
|
||||
this(url, zoomMin, zoomMax, "image/png", ".png");
|
||||
}
|
||||
|
||||
public BitmapTileSource(String url, int zoomMin, int zoomMax, String mimeType,
|
||||
String fileExtension) {
|
||||
super(url);
|
||||
mZoomMin = zoomMin;
|
||||
mZoomMax = zoomMax;
|
||||
mFileExtension = fileExtension;
|
||||
mMimeType = mimeType;
|
||||
}
|
||||
|
||||
public String getTileUrl(Tile tile) {
|
||||
return null;
|
||||
super(url, zoomMin, zoomMax);
|
||||
setExtension(".png");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITileDataSource getDataSource() {
|
||||
LwHttp conn = new LwHttp(mUrl, mMimeType, mFileExtension, false) {
|
||||
@Override
|
||||
protected int formatTilePath(Tile tile, byte[] path, int curPos) {
|
||||
String p = getTileUrl(tile);
|
||||
if (p == null)
|
||||
return super.formatTilePath(tile, path, curPos);
|
||||
|
||||
byte[] b = p.getBytes();
|
||||
System.arraycopy(b, 0, path, curPos, b.length);
|
||||
|
||||
return curPos + b.length;
|
||||
}
|
||||
};
|
||||
return new UrlTileDataSource(this, new BitmapTileDecoder(), conn);
|
||||
return new UrlTileDataSource(this, new BitmapTileDecoder(), new LwHttp(mUrl));
|
||||
}
|
||||
|
||||
public class BitmapTileDecoder implements ITileDecoder {
|
||||
|
@ -31,15 +31,15 @@ public class DefaultSources {
|
||||
|
||||
public static class ImagicoLandcover extends BitmapTileSource {
|
||||
public ImagicoLandcover() {
|
||||
super("http://www.imagico.de/map/tiles/landcover",
|
||||
0, 6, "image/jpeg", ".jpg");
|
||||
super("http://www.imagico.de/map/tiles/landcover", 0, 6);
|
||||
setExtension(".jpg");
|
||||
}
|
||||
}
|
||||
|
||||
public static class MapQuestAerial extends BitmapTileSource {
|
||||
public MapQuestAerial() {
|
||||
super("http://otile1.mqcdn.com/tiles/1.0.0/sat",
|
||||
0, 8, "image/jpeg", ".jpg");
|
||||
super("http://otile1.mqcdn.com/tiles/1.0.0/sat", 0, 8);
|
||||
setExtension(".jpg");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -60,14 +60,15 @@ public class DefaultSources {
|
||||
}
|
||||
|
||||
public static class ArcGISWorldShaded extends BitmapTileSource {
|
||||
private final StringBuilder sb = new StringBuilder(32);
|
||||
|
||||
public ArcGISWorldShaded() {
|
||||
super("http://server.arcgisonline.com/ArcGIS/rest/services",
|
||||
0, 6, "image/jpg", "");
|
||||
super("http://server.arcgisonline.com/ArcGIS/rest/services", 0, 6);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTileUrl(Tile tile) {
|
||||
StringBuilder sb = new StringBuilder(32);
|
||||
public synchronized String getTileUrl(Tile tile) {
|
||||
sb.setLength(0);
|
||||
//sb.append("/World_Imagery/MapServer/tile/");
|
||||
sb.append("/World_Shaded_Relief/MapServer/tile/");
|
||||
sb.append(tile.zoomLevel);
|
||||
@ -78,14 +79,15 @@ public class DefaultSources {
|
||||
}
|
||||
|
||||
public static class HillShadeHD extends BitmapTileSource {
|
||||
private final StringBuilder sb = new StringBuilder(32);
|
||||
|
||||
public HillShadeHD() {
|
||||
super("http://129.206.74.245:8004/tms_hs.ashx",
|
||||
2, 16, "image/png", "");
|
||||
super("http://129.206.74.245:8004/tms_hs.ashx", 2, 16);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTileUrl(Tile tile) {
|
||||
StringBuilder sb = new StringBuilder(32);
|
||||
public synchronized String getTileUrl(Tile tile) {
|
||||
sb.setLength(0);
|
||||
sb.append("?x=").append(tile.tileX);
|
||||
sb.append("&y=").append(tile.tileY);
|
||||
sb.append("&z=").append(tile.zoomLevel);
|
||||
@ -102,14 +104,15 @@ public class DefaultSources {
|
||||
*/
|
||||
public static class GoogleMaps extends BitmapTileSource {
|
||||
public static final GoogleMaps INSTANCE = new GoogleMaps("http://mt1.google.com");
|
||||
private final StringBuilder sb = new StringBuilder(60);
|
||||
|
||||
public GoogleMaps(String hostName) {
|
||||
super(hostName, 1, 20, "image/png", ""); //jpeg for sat
|
||||
super(hostName, 1, 20); //jpeg for sat
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTileUrl(Tile tile) {
|
||||
StringBuilder sb = new StringBuilder(60);
|
||||
public synchronized String getTileUrl(Tile tile) {
|
||||
sb.setLength(0);
|
||||
sb.append("/vt/x="); //lyrs=y&
|
||||
sb.append(tile.tileX);
|
||||
sb.append("&y=");
|
||||
|
@ -24,7 +24,6 @@ import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.URL;
|
||||
import java.util.zip.InflaterInputStream;
|
||||
|
||||
import org.oscim.core.Tile;
|
||||
import org.oscim.utils.ArrayUtils;
|
||||
@ -32,17 +31,18 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Lightweight HTTP connection for tile loading.
|
||||
* Lightweight HTTP connection for tile loading. Does not do redirects,
|
||||
* https, full header parsing or stuff.
|
||||
*
|
||||
* Default tile url format is 'z/x/y'. Override formatTilePath() for a
|
||||
* different format.
|
||||
* TODO extract API interface to be used by UrlTileSource so that one
|
||||
* could also use HttpUrlConnection, etc.
|
||||
*/
|
||||
public class LwHttp {
|
||||
static final Logger log = LoggerFactory.getLogger(LwHttp.class);
|
||||
static final boolean dbg = false;
|
||||
|
||||
private final static byte[] HEADER_HTTP_OK = "200 OK".getBytes();
|
||||
private final static byte[] HEADER_CONTENT_TYPE = "Content-Type".getBytes();
|
||||
//private final static byte[] HEADER_CONTENT_TYPE = "Content-Type".getBytes();
|
||||
private final static byte[] HEADER_CONTENT_LENGTH = "Content-Length".getBytes();
|
||||
private final static int RESPONSE_EXPECTED_LIVES = 100;
|
||||
private final static long RESPONSE_TIMEOUT = (long) 10E9; // 10 second in nanosecond
|
||||
@ -64,9 +64,6 @@ public class LwHttp {
|
||||
private final byte[] REQUEST_GET_END;
|
||||
private final byte[] mRequestBuffer;
|
||||
|
||||
private final boolean mInflateContent;
|
||||
private final byte[] mContentType;
|
||||
|
||||
/**
|
||||
* @param url
|
||||
* Base url for tiles
|
||||
@ -77,9 +74,7 @@ public class LwHttp {
|
||||
* @param deflate
|
||||
* true when content uses gzip compression
|
||||
*/
|
||||
public LwHttp(URL url, String contentType, String extension, boolean deflate) {
|
||||
mContentType = contentType.getBytes();
|
||||
mInflateContent = deflate;
|
||||
public LwHttp(URL url) {
|
||||
|
||||
int port = url.getPort();
|
||||
if (port < 0)
|
||||
@ -91,7 +86,7 @@ public class LwHttp {
|
||||
|
||||
REQUEST_GET_START = ("GET " + path).getBytes();
|
||||
|
||||
REQUEST_GET_END = (extension + " HTTP/1.1" +
|
||||
REQUEST_GET_END = (" HTTP/1.1" +
|
||||
"\nUser-Agent: vtm/0.5.9" +
|
||||
"\nHost: " + host +
|
||||
"\nConnection: Keep-Alive" +
|
||||
@ -229,7 +224,7 @@ public class LwHttp {
|
||||
}
|
||||
}
|
||||
|
||||
public InputStream readHeader() throws IOException {
|
||||
public InputStream read() throws IOException {
|
||||
|
||||
Buffer is = mResponseStream;
|
||||
is.mark(BUFFER_SIZE);
|
||||
@ -276,18 +271,17 @@ public class LwHttp {
|
||||
if (!check(HEADER_HTTP_OK, buf, pos + 9, end))
|
||||
ok = false;
|
||||
|
||||
} else if (check(HEADER_CONTENT_TYPE, buf, pos, end)) {
|
||||
// check that response contains the expected
|
||||
// Content-Type
|
||||
if (!check(mContentType, buf, pos +
|
||||
HEADER_CONTENT_TYPE.length + 2, end))
|
||||
ok = false;
|
||||
|
||||
} else if (check(HEADER_CONTENT_LENGTH, buf, pos, end)) {
|
||||
// parse Content-Length
|
||||
contentLength = parseInt(buf, pos +
|
||||
HEADER_CONTENT_LENGTH.length + 2, end - 1);
|
||||
}
|
||||
//} else if (check(HEADER_CONTENT_TYPE, buf, pos, end)) {
|
||||
// check that response contains the expected
|
||||
// Content-Type
|
||||
//if (!check(mContentType, buf, pos +
|
||||
// HEADER_CONTENT_TYPE.length + 2, end))
|
||||
// ok = false;
|
||||
|
||||
if (!ok || dbg) {
|
||||
String line = new String(buf, pos, end - pos - 1);
|
||||
@ -307,13 +301,10 @@ public class LwHttp {
|
||||
is.skip(end);
|
||||
is.start(contentLength);
|
||||
|
||||
if (mInflateContent)
|
||||
return new InflaterInputStream(is);
|
||||
|
||||
return is;
|
||||
}
|
||||
|
||||
public boolean sendRequest(Tile tile) throws IOException {
|
||||
public boolean sendRequest(UrlTileSource tileSource, Tile tile) throws IOException {
|
||||
|
||||
if (mSocket != null && ((mMaxReq-- <= 0)
|
||||
|| (System.nanoTime() - mLastRequest > RESPONSE_TIMEOUT))) {
|
||||
@ -344,7 +335,7 @@ public class LwHttp {
|
||||
byte[] request = mRequestBuffer;
|
||||
int pos = REQUEST_GET_START.length;
|
||||
|
||||
pos = formatTilePath(tile, request, pos);
|
||||
pos = tileSource.formatTilePath(tile, request, pos);
|
||||
|
||||
int len = REQUEST_GET_END.length;
|
||||
System.arraycopy(REQUEST_GET_END, 0, request, pos, len);
|
||||
@ -384,7 +375,7 @@ public class LwHttp {
|
||||
}
|
||||
|
||||
// write (positive) integer to byte array
|
||||
protected static int writeInt(int val, int pos, byte[] buf) {
|
||||
public static int writeInt(int val, int pos, byte[] buf) {
|
||||
if (val == 0) {
|
||||
buf[pos] = '0';
|
||||
return pos + 1;
|
||||
@ -444,23 +435,4 @@ public class LwHttp {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write custom tile url
|
||||
*
|
||||
* @param tile Tile
|
||||
* @param path to write url string
|
||||
* @param curPos current position
|
||||
* @return new position
|
||||
*/
|
||||
protected int formatTilePath(Tile tile, byte[] request, int pos) {
|
||||
request[pos++] = '/';
|
||||
pos = writeInt(tile.zoomLevel, pos, request);
|
||||
request[pos++] = '/';
|
||||
pos = writeInt(tile.tileX, pos, request);
|
||||
request[pos++] = '/';
|
||||
pos = writeInt(tile.tileY, pos, request);
|
||||
return pos;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -29,7 +29,6 @@ import org.oscim.tiling.source.ITileCache.TileWriter;
|
||||
import org.oscim.tiling.source.ITileDataSink;
|
||||
import org.oscim.tiling.source.ITileDataSource;
|
||||
import org.oscim.tiling.source.ITileDecoder;
|
||||
import org.oscim.tiling.source.TileSource;
|
||||
import org.oscim.utils.IOUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -39,20 +38,22 @@ public class UrlTileDataSource implements ITileDataSource {
|
||||
|
||||
protected final LwHttp mConn;
|
||||
protected final ITileDecoder mTileDecoder;
|
||||
protected final ITileCache mTileCache;
|
||||
protected final UrlTileSource mTileSource;
|
||||
protected final boolean mUseCache;
|
||||
|
||||
public UrlTileDataSource(TileSource tileSource, ITileDecoder tileDecoder, LwHttp conn) {
|
||||
public UrlTileDataSource(UrlTileSource tileSource, ITileDecoder tileDecoder, LwHttp conn) {
|
||||
mTileDecoder = tileDecoder;
|
||||
mTileCache = tileSource.tileCache;
|
||||
mUseCache = (mTileCache != null);
|
||||
mTileSource = tileSource;
|
||||
mUseCache = (tileSource.tileCache != null);
|
||||
mConn = conn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryResult executeQuery(MapTile tile, ITileDataSink sink) {
|
||||
ITileCache cache = mTileSource.tileCache;
|
||||
|
||||
if (mUseCache) {
|
||||
TileReader c = mTileCache.getTile(tile);
|
||||
TileReader c = cache.getTile(tile);
|
||||
if (c != null) {
|
||||
InputStream is = c.getInputStream();
|
||||
try {
|
||||
@ -68,17 +69,17 @@ public class UrlTileDataSource implements ITileDataSource {
|
||||
}
|
||||
|
||||
boolean success = false;
|
||||
TileWriter cache = null;
|
||||
TileWriter cacheWriter = null;
|
||||
try {
|
||||
InputStream is;
|
||||
if (!mConn.sendRequest(tile)) {
|
||||
if (!mConn.sendRequest(mTileSource, tile)) {
|
||||
log.debug("{} Request failed", tile);
|
||||
} else if ((is = mConn.readHeader()) == null) {
|
||||
} else if ((is = mConn.read()) == null) {
|
||||
log.debug("{} Network Error", tile);
|
||||
} else {
|
||||
if (mUseCache) {
|
||||
cache = mTileCache.writeTile(tile);
|
||||
mConn.setCache(cache.getOutputStream());
|
||||
cacheWriter = cache.writeTile(tile);
|
||||
mConn.setCache(cacheWriter.getOutputStream());
|
||||
}
|
||||
|
||||
success = mTileDecoder.decode(tile, sink, is);
|
||||
@ -94,8 +95,8 @@ public class UrlTileDataSource implements ITileDataSource {
|
||||
} finally {
|
||||
mConn.requestCompleted(success);
|
||||
|
||||
if (cache != null)
|
||||
cache.complete(success);
|
||||
if (cacheWriter != null)
|
||||
cacheWriter.complete(success);
|
||||
}
|
||||
return success ? QueryResult.SUCCESS : QueryResult.FAILED;
|
||||
}
|
||||
|
@ -19,11 +19,13 @@ package org.oscim.tiling.source.common;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
import org.oscim.core.Tile;
|
||||
import org.oscim.tiling.source.TileSource;
|
||||
|
||||
public abstract class UrlTileSource extends TileSource {
|
||||
|
||||
protected final URL mUrl;
|
||||
private byte[] mExt;
|
||||
|
||||
public UrlTileSource(String urlString) {
|
||||
URL url = null;
|
||||
@ -35,6 +37,12 @@ public abstract class UrlTileSource extends TileSource {
|
||||
mUrl = url;
|
||||
}
|
||||
|
||||
public UrlTileSource(String url, int zoomMin, int zoomMax) {
|
||||
this(url);
|
||||
mZoomMin = zoomMin;
|
||||
mZoomMax = zoomMax;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OpenResult open() {
|
||||
return OpenResult.SUCCESS;
|
||||
@ -44,4 +52,55 @@ public abstract class UrlTileSource extends TileSource {
|
||||
public void close() {
|
||||
|
||||
}
|
||||
|
||||
protected void setExtension(String ext) {
|
||||
if (ext == null) {
|
||||
mExt = null;
|
||||
return;
|
||||
}
|
||||
mExt = ext.getBytes();
|
||||
}
|
||||
|
||||
protected void setMimeType(String string) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create url path for tile
|
||||
*/
|
||||
protected String getTileUrl(Tile tile) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write tile url - the low level, no-allocations method,
|
||||
*
|
||||
* override getTileUrl() for custom url formatting using
|
||||
* Strings
|
||||
*
|
||||
* @param tile Tile
|
||||
* @param path to write url string
|
||||
* @param curPos current position
|
||||
* @return new position
|
||||
*/
|
||||
protected int formatTilePath(Tile tile, byte[] buf, int pos) {
|
||||
String p = getTileUrl(tile);
|
||||
if (p != null) {
|
||||
byte[] b = p.getBytes();
|
||||
System.arraycopy(b, 0, buf, pos, b.length);
|
||||
return pos + b.length;
|
||||
}
|
||||
|
||||
buf[pos++] = '/';
|
||||
pos = LwHttp.writeInt(tile.zoomLevel, pos, buf);
|
||||
buf[pos++] = '/';
|
||||
pos = LwHttp.writeInt(tile.tileX, pos, buf);
|
||||
buf[pos++] = '/';
|
||||
pos = LwHttp.writeInt(tile.tileY, pos, buf);
|
||||
if (mExt == null)
|
||||
return pos;
|
||||
|
||||
System.arraycopy(mExt, 0, buf, pos, mExt.length);
|
||||
return pos + mExt.length;
|
||||
}
|
||||
}
|
||||
|
@ -30,8 +30,9 @@ public class MapnikVectorTileSource extends UrlTileSource {
|
||||
|
||||
@Override
|
||||
public ITileDataSource getDataSource() {
|
||||
LwHttp conn = new LwHttp(mUrl, "image/png", ".vector.pbf", true) {
|
||||
@Override
|
||||
return new UrlTileDataSource(this, new TileDecoder(), new LwHttp(mUrl));
|
||||
}
|
||||
|
||||
protected int formatTilePath(Tile tile, byte[] path, int pos) {
|
||||
// url formatter for mapbox streets
|
||||
byte[] hexTable = {
|
||||
@ -50,9 +51,7 @@ public class MapnikVectorTileSource extends UrlTileSource {
|
||||
pos = LwHttp.writeInt(tile.tileX, pos, path);
|
||||
path[pos++] = '/';
|
||||
pos = LwHttp.writeInt(tile.tileY, pos, path);
|
||||
|
||||
return pos;
|
||||
}
|
||||
};
|
||||
return new UrlTileDataSource(this, new TileDecoder(), conn);
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ package org.oscim.tiling.source.mapnik;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.zip.InflaterInputStream;
|
||||
|
||||
import org.oscim.core.GeometryBuffer.GeometryType;
|
||||
import org.oscim.core.MapElement;
|
||||
@ -77,7 +78,7 @@ public class TileDecoder extends PbfDecoder {
|
||||
if (debug)
|
||||
log.debug(tile + " decode");
|
||||
|
||||
setInputStream(is);
|
||||
setInputStream(new InflaterInputStream(is));
|
||||
mTile = tile;
|
||||
mMapDataCallback = mapDataCallback;
|
||||
mScale = REF_TILE_SIZE / Tile.SIZE;
|
||||
|
@ -29,11 +29,12 @@ public class OSciMap1TileSource extends UrlTileSource {
|
||||
|
||||
public OSciMap1TileSource(String url) {
|
||||
super(url);
|
||||
setExtension(".osmtile");
|
||||
setMimeType("application/osmtile");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITileDataSource getDataSource() {
|
||||
LwHttp conn = new LwHttp(mUrl, "application/osmtile", ".osmtile", false);
|
||||
return new UrlTileDataSource(this, new TileDecoder(), conn);
|
||||
return new UrlTileDataSource(this, new TileDecoder(), new LwHttp(mUrl));
|
||||
}
|
||||
}
|
||||
|
@ -38,12 +38,13 @@ public class OSciMap2TileSource extends UrlTileSource {
|
||||
|
||||
public OSciMap2TileSource(String url) {
|
||||
super(url);
|
||||
setExtension(".osmtile");
|
||||
setMimeType("application/osmtile");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITileDataSource getDataSource() {
|
||||
LwHttp conn = new LwHttp(mUrl, "application/osmtile", ".osmtile", false);
|
||||
return new UrlTileDataSource(this, new TileDecoder(), conn);
|
||||
return new UrlTileDataSource(this, new TileDecoder(), new LwHttp(mUrl));
|
||||
}
|
||||
|
||||
static class TileDecoder extends PbfDecoder {
|
||||
|
@ -24,17 +24,19 @@ import org.oscim.tiling.source.common.UrlTileSource;
|
||||
public class OSciMap4TileSource extends UrlTileSource {
|
||||
|
||||
public OSciMap4TileSource() {
|
||||
super("http://opensciencemap.org/tiles/vtm");
|
||||
this("http://opensciencemap.org/tiles/vtm");
|
||||
}
|
||||
|
||||
public OSciMap4TileSource(String url) {
|
||||
super(url);
|
||||
setExtension(".vtm");
|
||||
// ignored for now
|
||||
//setMimeType("image/png");
|
||||
//setMimeType("application/x-protobuf");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITileDataSource getDataSource() {
|
||||
//LwHttp conn = new LwHttp(url, "application/x-protobuf", ".vtm", false);
|
||||
LwHttp conn = new LwHttp(mUrl, "image/png", ".vtm", false);
|
||||
return new UrlTileDataSource(this, new TileDecoder(), conn);
|
||||
return new UrlTileDataSource(this, new TileDecoder(), new LwHttp(mUrl));
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user