api: UrlTileSource:

- add UrlTileSource.getTileUrl(Tile) to create complete url string
- add TileUrlFormatter interface to override default formatter
- remove unused return from sendRequest()
This commit is contained in:
Hannes Janetzek 2014-04-03 16:08:39 +02:00
parent 6b7ccd68c9
commit 85a4bbe125
9 changed files with 121 additions and 106 deletions

View File

@ -25,32 +25,34 @@ public class MapnikVectorTileSource extends UrlTileSource {
public MapnikVectorTileSource() { public MapnikVectorTileSource() {
super("http://d1s11ojcu7opje.cloudfront.net/dev/764e0b8d", ""); 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 @Override
public ITileDataSource getDataSource() { public ITileDataSource getDataSource() {
return new UrlTileDataSource(this, new TileDecoder(), getHttpEngine()); 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();
}
} }

View File

@ -17,7 +17,6 @@ package org.oscim.tiling.source;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.URL;
import org.oscim.core.Tile; import org.oscim.core.Tile;
import org.oscim.layers.tile.MapTile; import org.oscim.layers.tile.MapTile;
@ -31,15 +30,12 @@ import com.google.gwt.xhr.client.XMLHttpRequest.ResponseType;
public class LwHttp implements HttpEngine { public class LwHttp implements HttpEngine {
//static final Logger log = LoggerFactory.getLogger(LwHttp.class); //static final Logger log = LoggerFactory.getLogger(LwHttp.class);
private final String mUrlPath;
private XMLHttpRequest mHttpRequest; private XMLHttpRequest mHttpRequest;
private ReadyStateChangeHandler mResponseHandler; private ReadyStateChangeHandler mResponseHandler;
public LwHttp(UrlTileSource tileSource) { public LwHttp(UrlTileSource tileSource) {
mTileSource = tileSource; mTileSource = tileSource;
URL url = tileSource.getUrl();
mUrlPath = url.toString();
} }
static class Buffer extends InputStream { static class Buffer extends InputStream {
@ -72,9 +68,9 @@ public class LwHttp implements HttpEngine {
private UrlTileSource mTileSource; 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 = XMLHttpRequest.create();
mHttpRequest.open("GET", url); mHttpRequest.open("GET", url);
@ -101,8 +97,6 @@ public class LwHttp implements HttpEngine {
mHttpRequest.setOnReadyStateChange(mResponseHandler); mHttpRequest.setOnReadyStateChange(mResponseHandler);
mHttpRequest.send(); mHttpRequest.send();
return true;
} }
public static class LwHttpFactory implements HttpEngine.Factory { public static class LwHttpFactory implements HttpEngine.Factory {
@ -130,7 +124,6 @@ public class LwHttp implements HttpEngine {
} }
@Override @Override
public boolean sendRequest(Tile tile) throws IOException { public void sendRequest(Tile tile) throws IOException {
return false;
} }
} }

View File

@ -60,8 +60,7 @@ public class BitmapTileSource extends UrlTileSource {
@Override @Override
public void query(final MapTile tile, final ITileDataSink sink) { public void query(final MapTile tile, final ITileDataSink sink) {
String url = mTileSource.getUrl() String url = mTileSource.getTileUrl(tile);
+ BitmapTileSource.this.formatTilePath(tile);
SafeUri uri = UriUtils.fromTrustedString(url); SafeUri uri = UriUtils.fromTrustedString(url);

View File

@ -59,10 +59,7 @@ public class JsonTileDataSource implements ITileDataSource {
mSink = sink; mSink = sink;
try { try {
String url = mTileSource.getUrl() doGet(mTileSource.getTileUrl(tile));
+ mTileSource.formatTilePath(tile);
doGet(url);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
sink.completed(FAILED); sink.completed(FAILED);

View File

@ -26,7 +26,7 @@ public interface HttpEngine {
InputStream read() throws IOException; InputStream read() throws IOException;
boolean sendRequest(Tile tile) throws IOException; void sendRequest(Tile tile) throws IOException;
void close(); void close();

View File

@ -53,7 +53,7 @@ public class LwHttp implements HttpEngine {
private final String mHost; private final String mHost;
private final int mPort; private final int mPort;
private int mMaxReq = 0; private int mMaxRequests = 0;
private Socket mSocket; private Socket mSocket;
private OutputStream mCommandStream; private OutputStream mCommandStream;
private Buffer mResponseStream; private Buffer mResponseStream;
@ -66,10 +66,13 @@ public class LwHttp implements HttpEngine {
private final byte[] REQUEST_GET_START; private final byte[] REQUEST_GET_START;
private final byte[] REQUEST_GET_END; private final byte[] REQUEST_GET_END;
private final byte[] mRequestBuffer; private final byte[] mRequestBuffer;
private final byte[][] mTilePath; private final byte[][] mTilePath;
private final UrlTileSource mTileSource;
private LwHttp(UrlTileSource tileSource, byte[][] tilePath) { private LwHttp(UrlTileSource tileSource, byte[][] tilePath) {
mTilePath = tilePath; mTilePath = tilePath;
mTileSource = tileSource;
URL url = tileSource.getUrl(); URL url = tileSource.getUrl();
int port = url.getPort(); int port = url.getPort();
@ -109,6 +112,7 @@ public class LwHttp implements HttpEngine {
// to avoid a copy in PbfDecoder one could manage the buffer // to avoid a copy in PbfDecoder one could manage the buffer
// array directly and provide access to it. // array directly and provide access to it.
static class Buffer extends BufferedInputStream { static class Buffer extends BufferedInputStream {
static final class Buffer extends BufferedInputStream {
OutputStream cache; OutputStream cache;
int bytesRead = 0; int bytesRead = 0;
int bytesWrote; int bytesWrote;
@ -188,6 +192,7 @@ public class LwHttp implements HttpEngine {
if (marked >= 0) if (marked >= 0)
bytesRead = marked; bytesRead = marked;
/* TODO could check if the mark is already invalid */ /* TODO could check if the mark is already invalid */
super.reset(); super.reset();
} }
@ -323,17 +328,19 @@ public class LwHttp implements HttpEngine {
} }
@Override @Override
public boolean sendRequest(Tile tile) throws IOException { public void sendRequest(Tile tile) throws IOException {
if (mSocket != null) { if (mSocket != null) {
if (mMaxReq-- <= 0) if (--mMaxRequests < 0)
close(); close();
else if (System.nanoTime() - mLastRequest > RESPONSE_TIMEOUT) else if (System.nanoTime() - mLastRequest > RESPONSE_TIMEOUT)
close(); close();
else { else {
try { try {
if (mResponseStream.available() > 0) if (mResponseStream.available() > 0) {
log.debug("still bytes available");
close(); close();
}
} catch (IOException e) { } catch (IOException e) {
log.debug(e.getMessage()); log.debug(e.getMessage());
close(); close();
@ -346,36 +353,32 @@ public class LwHttp implements HttpEngine {
lwHttpConnect(); lwHttpConnect();
/* TODO parse from header */ /* TODO parse from header */
mMaxReq = RESPONSE_EXPECTED_LIVES; mMaxRequests = RESPONSE_EXPECTED_LIVES;
} }
byte[] request = mRequestBuffer;
int pos = REQUEST_GET_START.length; int pos = REQUEST_GET_START.length;
pos = formatTilePath(tile, request, pos);
int len = REQUEST_GET_END.length; 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; len += pos;
if (dbg) if (dbg)
log.debug("request: {}", new String(request, 0, len)); log.debug("request: {}", new String(mRequestBuffer, 0, len));
try { try {
mCommandStream.write(request, 0, len); writeRequest(mRequestBuffer, len);
mCommandStream.flush();
return true;
} catch (IOException e) { } catch (IOException e) {
log.debug("recreate connection"); log.debug("recreate connection");
close(); close();
/* might throw IOException */
lwHttpConnect(); lwHttpConnect();
writeRequest(mRequestBuffer, len);
mCommandStream.write(request, 0, len);
mCommandStream.flush();
} }
}
return true; private void writeRequest(byte[] request, int length) throws IOException {
mCommandStream.write(request, 0, length);
mCommandStream.flush();
} }
private boolean lwHttpConnect() throws IOException { private boolean lwHttpConnect() throws IOException {
@ -500,10 +503,19 @@ public class LwHttp implements HttpEngine {
* @return new position * @return new position
*/ */
private int formatTilePath(Tile tile, byte[] buf, int pos) { 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) { for (byte[] b : mTilePath) {
if (b.length == 1) { if (b.length == 1) {
if (b[0] == '/') { if (b[0] == '/') {
buf[pos++] = '/'; buf[pos++] = '/';
continue;
} else if (b[0] == 'X') { } else if (b[0] == 'X') {
pos = writeInt(tile.tileX, pos, buf); pos = writeInt(tile.tileX, pos, buf);
continue; continue;
@ -527,13 +539,16 @@ public class LwHttp implements HttpEngine {
@Override @Override
public HttpEngine create(UrlTileSource tileSource) { 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) { if (mTilePath == null) {
String[] path = tileSource.getTilePath(); String[] path = tileSource.getTilePath();
mTilePath = new byte[path.length][]; mTilePath = new byte[path.length][];
for (int i = 0; i < path.length; i++) for (int i = 0; i < path.length; i++)
mTilePath[i] = path[i].getBytes(); mTilePath[i] = path[i].getBytes();
} }
return new LwHttp(tileSource, mTilePath); return new LwHttp(tileSource, mTilePath);
} }
} }

View File

@ -21,10 +21,10 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import org.oscim.core.Tile; import org.oscim.core.Tile;
import org.oscim.utils.IOUtils;
import com.squareup.okhttp.OkHttpClient; import com.squareup.okhttp.OkHttpClient;
@ -57,33 +57,20 @@ public class OkHttpEngine implements HttpEngine {
return inputStream; return inputStream;
} }
HttpURLConnection openConnection(Tile tile) throws MalformedURLException {
return mClient.open(new URL(mTileSource.getUrl() +
mTileSource.formatTilePath(tile)));
}
@Override @Override
public boolean sendRequest(Tile tile) throws IOException { public void sendRequest(Tile tile) throws IOException {
if (tile == null) { if (tile == null) {
throw new IllegalArgumentException("Tile cannot be 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 = conn.getInputStream();
inputStream = connection.getInputStream();
return true;
} }
@Override @Override
public void close() { public void close() {
if (inputStream != null) { IOUtils.closeQuietly(inputStream);
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} }
@Override @Override

View File

@ -74,10 +74,9 @@ public class UrlTileDataSource implements ITileDataSource {
boolean success = false; boolean success = false;
TileWriter cacheWriter = null; TileWriter cacheWriter = null;
try { try {
InputStream is; mConn.sendRequest(tile);
if (!mConn.sendRequest(tile)) { InputStream is = mConn.read();
log.debug("{} Request failed", tile); if (is == null) {
} else if ((is = mConn.read()) == null) {
log.debug("{} Network Error", tile); log.debug("{} Network Error", tile);
} else { } else {
if (mUseCache) { if (mUseCache) {

View File

@ -26,11 +26,18 @@ import org.oscim.tiling.source.LwHttp.LwHttpFactory;
public abstract class UrlTileSource extends TileSource { public abstract class UrlTileSource extends TileSource {
public final static TileUrlFormatter URL_FORMATTER = new DefaultTileUrlFormatter();
private final URL mUrl; private final URL mUrl;
private final String[] mTilePath; private final String[] mTilePath;
private HttpEngine.Factory mHttpFactory; private HttpEngine.Factory mHttpFactory;
private Map<String, String> mRequestHeaders; private Map<String, String> 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) { public UrlTileSource(String url, String tilePath, int zoomMin, int zoomMax) {
this(url, tilePath); this(url, tilePath);
@ -72,29 +79,8 @@ public abstract class UrlTileSource extends TileSource {
return mUrl; return mUrl;
} }
public String formatTilePath(Tile tile) { public String getTileUrl(Tile tile) {
// TODO only use the actual replacement positions. return mUrl + mTileUrlFormatter.formatTilePath(this, tile);
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 void setHttpEngine(HttpEngine.Factory httpFactory) { public void setHttpEngine(HttpEngine.Factory httpFactory) {
@ -113,11 +99,48 @@ public abstract class UrlTileSource extends TileSource {
return mTilePath; return mTilePath;
} }
/**
*
*/
public void setUrlFormatter(TileUrlFormatter formatter) {
mTileUrlFormatter = formatter;
}
public TileUrlFormatter getUrlFormatter() {
return mTileUrlFormatter;
}
public HttpEngine getHttpEngine() { public HttpEngine getHttpEngine() {
if (mHttpFactory == null) { if (mHttpFactory == null) {
mHttpFactory = new LwHttpFactory(); mHttpFactory = new LwHttpFactory();
} }
return mHttpFactory.create(this); 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();
}
}
} }