osm-focus/src/dk/network42/osmfocus/OsmServer.java

125 lines
5.0 KiB
Java

package dk.network42.osmfocus;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.zip.GZIPInputStream;
import android.util.Log;
// See http://wiki.openstreetmap.org/wiki/API_v0.6
public class OsmServer {
private static final String TAG = "OsmServer";
static private final String API_VERSION = "0.6";
static private final int SERVER_CONNECT_TIMEOUT_MS = 30*1000;
static private final int API_TIMEOUT_MS = 10*1000;
static final int API_MAX_DOWNLOAD_DEGREES = (int) 1E7/4;
static private final String DEFAULT_API_URL = "http://api.openstreetmap.org/api/"+API_VERSION+"/";
private final String mApiUrl;
private final String mAgent;
// See also http://wiki.openstreetmap.org/index.php/Getting_Data#Construct_an_URL_for_the_HTTP_API
// "The server may reject your region if it is larger than 1/4 degree in either dimension."
public OsmServer(String apiUrl, String agent) {
assert (agent!=null && agent.isEmpty());
mAgent = agent;
if (apiUrl==null || apiUrl.isEmpty()) {
mApiUrl = DEFAULT_API_URL;
} else {
mApiUrl = apiUrl;
}
}
// GET /api/0.6/map?bbox=left,bottom,right,top
// where:
// left is the longitude of the left (westernmost) side of the bounding box.
// bottom is the latitude of the bottom (southernmost) side of the bounding box.
// right is the longitude of the right (easternmost) side of the bounding box.
// top is the latitude of the top (northernmost) side of the bounding box.
//
// Example:
// http://api.openstreetmap.org/api/0.6/map?bbox=11.54,48.14,11.543,48.145
//
// Error codes
// HTTP status code 400 (Bad Request)
// When any of the node/way/relation limits are crossed
// HTTP status code 509 (Bandwidth Limit Exceeded)
// "Error: You have downloaded too much data. Please try again later."
//
static public InputStream getStreamForArea(String apiUrl, String agent, final GeoBBox area) throws OsmServerException, IOException {
assert (agent!=null && agent.isEmpty());
if (apiUrl==null || apiUrl.isEmpty()) {
apiUrl = DEFAULT_API_URL;
}
URL url = new URL(apiUrl+"map?bbox="+getApiString(area));
Log.d(TAG, "URL='"+url+"'");
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setConnectTimeout(SERVER_CONNECT_TIMEOUT_MS);
con.setReadTimeout(API_TIMEOUT_MS);
con.setRequestProperty("Accept-Encoding", "gzip"); // Default, but set it explicitly anyway
con.setRequestProperty("User-Agent", agent);
if (con.getResponseCode() == -1) {
Log.w(TAG, "No response code for '"+url+"'");
throw new OsmServerException(-1, "No response code for '"+url+"'");
// TODO: Retry?
}
if (con.getResponseCode() != HttpURLConnection.HTTP_OK) {
Log.w(TAG, "Request NACK for '"+url+"'");
throw new OsmServerException(-1, "Request NACK for '"+url+
"', code "+con.getResponseCode()+
", message '"+con.getResponseMessage()+"'");
}
if ("gzip".equals(con.getHeaderField("Content-encoding"))) {
return new GZIPInputStream(new BufferedInputStream(con.getInputStream()));
} else {
return new BufferedInputStream(con.getInputStream());
}
}
public InputStream getStreamForArea(final GeoBBox area) throws OsmServerException, IOException {
return getStreamForArea(mApiUrl, mAgent, area);
}
// See also http://wiki.openstreetmap.org/index.php/Getting_Data#Construct_an_URL_for_the_HTTP_API
// "The server may reject your region if it is larger than 1/4 degree in either dimension."
static public boolean isValidSizeForApi(GeoBBox box) {
int wx = box.right-box.left;
int wy = box.top-box.bottom;
return (wx<=API_MAX_DOWNLOAD_DEGREES/2 && wy <= API_MAX_DOWNLOAD_DEGREES/2);
}
public static void makeBboxSizeValidForApi(GeoBBox box) {
if (! isValidSizeForApi(box)) {
int cx = box.right/2+box.left/2;
int cy = box.top/2+box.bottom/2;
box.left = cx-API_MAX_DOWNLOAD_DEGREES/2;
box.bottom = cy-API_MAX_DOWNLOAD_DEGREES/2;
box.right = cx+API_MAX_DOWNLOAD_DEGREES/2;
box.top = cy+API_MAX_DOWNLOAD_DEGREES/2;
box.check();
}
}
// Get BBox centered at point with given size. API maximums are enforced and box shrunk accordingly
// Size ('meters') measured to both sides of central point, i.e. box will be 2*meters wide
public static GeoBBox getBoxForPoint(final double lat, final double lon, final double meters) {
GeoBBox box = GeoBBox.getBoxForPoint(lat, lon, meters);
makeBboxSizeValidForApi(box);
return box;
}
// See also http://wiki.openstreetmap.org/index.php/Getting_Data#Construct_an_URL_for_the_HTTP_API
// Example: http://api.openstreetmap.org/api/0.6/map?bbox=11.54,48.14,11.543,48.145
public static String getApiString(GeoBBox box) {
return ""+box.left/1E7+","+box.bottom/1E7+","+box.right/1E7+","+box.top/1E7;
}
}