From 92599213455f8661de96f02168cd9d41f93638dc Mon Sep 17 00:00:00 2001 From: Nicco Kunzmann Date: Tue, 3 Sep 2019 19:53:10 +0200 Subject: [PATCH] refactor local web server handler class - create handler package - add handler for own plants - contributes to https://github.com/niccokunzmann/mundraub-android/issues/81 --- .../mundraub/map/MundraubMapAPI.java | 67 ++----------------- .../mundraub/map/MundraubMapAPIForApp.java | 49 +++----------- .../mundraub/map/handler/ErrorHandler.java | 5 ++ .../map/handler/PlantCollectionHandler.java | 37 ++++++++++ .../mundraub/map/handler/TilesHandler.java | 50 ++++++++++++++ .../mundraub/map/handler/URIHandler.java | 64 ++++++++++++++++++ .../eu/quelltext/mundraub/plant/Plant.java | 2 +- 7 files changed, 172 insertions(+), 102 deletions(-) create mode 100644 app/src/main/java/eu/quelltext/mundraub/map/handler/ErrorHandler.java create mode 100644 app/src/main/java/eu/quelltext/mundraub/map/handler/PlantCollectionHandler.java create mode 100644 app/src/main/java/eu/quelltext/mundraub/map/handler/TilesHandler.java create mode 100644 app/src/main/java/eu/quelltext/mundraub/map/handler/URIHandler.java diff --git a/app/src/main/java/eu/quelltext/mundraub/map/MundraubMapAPI.java b/app/src/main/java/eu/quelltext/mundraub/map/MundraubMapAPI.java index 1e8bc64..a12ad5e 100644 --- a/app/src/main/java/eu/quelltext/mundraub/map/MundraubMapAPI.java +++ b/app/src/main/java/eu/quelltext/mundraub/map/MundraubMapAPI.java @@ -1,16 +1,15 @@ package eu.quelltext.mundraub.map; -import org.apache.commons.lang3.exception.ExceptionUtils; import org.nanohttpd.protocols.http.IHTTPSession; import org.nanohttpd.protocols.http.NanoHTTPD; -import org.nanohttpd.protocols.http.request.Method; import org.nanohttpd.protocols.http.response.Response; import org.nanohttpd.protocols.http.response.Status; -import org.nanohttpd.util.IHandler; import java.io.IOException; import java.io.UnsupportedEncodingException; +import eu.quelltext.mundraub.map.handler.ErrorHandler; +import eu.quelltext.mundraub.map.handler.URIHandler; import okhttp3.HttpUrl; import okhttp3.OkHttpClient; import okhttp3.Request; @@ -20,7 +19,7 @@ This is a proxy to the Mundraub API for the map. It can be extended to cache plants. */ -public class MundraubMapAPI extends NanoHTTPD implements MundraubProxy { +public class MundraubMapAPI extends NanoHTTPD implements MundraubProxy, ErrorHandler { private final static int DEFAULT_PORT = 39768; private static final String API_PATH_TRANSLATIONS = "/translations/app.js"; @@ -69,62 +68,10 @@ public Response serve(IHTTPSession session) { return Response.newFixedLengthResponse(Status.NOT_FOUND, NanoHTTPD.MIME_HTML, msg); } - protected class URIHandler implements IHandler { - - private final String uri; - - public URIHandler(String uri) { - this.uri = uri; - } - - @Override - public Response handle(IHTTPSession input) { - if (wantsToServe(input)) { - Response response; - try { - response = respondTo(input); - } catch (Exception e) { - response = handleError(e); - } - response.addHeader("Access-Control-Allow-Origin", "*"); // allow JavaScript to access the content - return response; - } - return null; - } - - public Response respondTo(IHTTPSession input) throws Exception { - return null; - } - - public boolean wantsToServe(IHTTPSession input) { - return wantsToHandleMethod(input.getMethod()) && - wantsToServeURI(input.getUri()); - } - - public boolean wantsToServeURI(String uri) { - return uri.equals(this.uri); - } - - public boolean wantsToHandleMethod(Method method) { - return method == Method.GET; - } - - public Response handleError(Exception e) { - MundraubMapAPI.this.handleError(e); - String msg = "

500 Internal server errir

\n" + - "
" + ExceptionUtils.getStackTrace(e) + "
"; - return Response.newFixedLengthResponse(Status.INTERNAL_ERROR, NanoHTTPD.MIME_HTML, msg); - } - - protected String baseUri() { - return uri; - } - } - - protected class PlantHandler extends URIHandler { + protected class PlantHandler extends URIHandler { protected PlantHandler(String uri) { - super(uri); + super(uri, MundraubMapAPI.this); } public Response respondTo(IHTTPSession input) throws Exception { @@ -145,7 +92,7 @@ protected byte[] getResponseBytesFromPlantMarkerQuery(String queryParameterStrin return response.body().bytes(); } - protected void handleError(Exception e) { + public void handleError(Exception e) { e.printStackTrace(); } @@ -175,7 +122,7 @@ protected OkHttpClient client() { protected class TranslationsHandler extends URIHandler { public TranslationsHandler(String uri) { - super(uri); + super(uri, MundraubMapAPI.this); } @Override diff --git a/app/src/main/java/eu/quelltext/mundraub/map/MundraubMapAPIForApp.java b/app/src/main/java/eu/quelltext/mundraub/map/MundraubMapAPIForApp.java index 6ee2b05..828a920 100644 --- a/app/src/main/java/eu/quelltext/mundraub/map/MundraubMapAPIForApp.java +++ b/app/src/main/java/eu/quelltext/mundraub/map/MundraubMapAPIForApp.java @@ -5,9 +5,6 @@ import org.json.JSONException; import org.json.JSONObject; -import org.nanohttpd.protocols.http.IHTTPSession; -import org.nanohttpd.protocols.http.response.Response; -import org.nanohttpd.protocols.http.response.Status; import java.io.IOException; import java.io.UnsupportedEncodingException; @@ -15,22 +12,27 @@ import eu.quelltext.mundraub.common.Settings; import eu.quelltext.mundraub.error.Logger; import eu.quelltext.mundraub.initialization.Initialization; +import eu.quelltext.mundraub.map.handler.PlantCollectionHandler; +import eu.quelltext.mundraub.map.handler.TilesHandler; +import eu.quelltext.mundraub.plant.Plant; import eu.quelltext.mundraub.plant.PlantCategory; import okhttp3.OkHttpClient; public class MundraubMapAPIForApp extends MundraubMapAPI { private final Logger.Log log; + private final static String PATH_PLANTS = "/cluster/my-plants"; public MundraubMapAPIForApp() { super(Settings.hostForMundraubAPI()); log = Logger.newFor(this); - addHTTPInterceptor(new TilesHandler(MapUrl.PATH_SATELITE, TilesCache.forSatellite())); - addHTTPInterceptor(new TilesHandler(MapUrl.PATH_OSM, TilesCache.forOSM())); + addHTTPInterceptor(new TilesHandler(this, MapUrl.PATH_SATELITE, TilesCache.forSatellite(), this, this.log)); + addHTTPInterceptor(new TilesHandler(this, MapUrl.PATH_OSM, TilesCache.forOSM(), this, this.log)); + addHTTPInterceptor(new PlantCollectionHandler(PATH_PLANTS, Plant.getPlants(), this)); } @Override - protected void handleError(Exception e) { + public void handleError(Exception e) { log.printStackTrace(e); } @@ -70,39 +72,4 @@ protected byte[] getResponseBytesForAppTranslations() throws UnsupportedEncoding return json.toString().getBytes("UTF-8"); } - protected class TilesHandler extends URIHandler { - private final TilesCache cache; - - public TilesHandler(String uri, TilesCache cache) { - super(uri); - this.cache = cache; - } - - @Override - public boolean wantsToServeURI(String uri) { - return uri.startsWith(baseUri()); - } - - public Response respondTo(IHTTPSession input) throws Exception { - String[] zyx = input.getUri().substring(this.baseUri().length()).split("/"); - if (zyx.length < 3) { - return Response.newFixedLengthResponse(Status.INTERNAL_ERROR, MIME_PLAINTEXT, "I need " + baseUri() + "z/y/x"); - } - int x = Integer.parseInt(zyx[zyx.length - 1]); - int y = Integer.parseInt(zyx[zyx.length - 2]); - int z = Integer.parseInt(zyx[zyx.length - 3]); - TilesCache.Tile tile = cache.getTileAt(x, y, z); - if (tile.isCached()) { - log.d("handle tile", 200 + ": " + z + "/" + y + "/" + x); - Response response = Response.newFixedLengthResponse(Status.OK, tile.contentType(), tile.bytes()); - response.addHeader("Cache-Control", "no-store, must-revalidate"); // no cache from https://stackoverflow.com/a/2068407 - return response; - } else { - log.d("handle tile", 307 + ": " + z + "/" + y + "/" + x + " -> " + tile.url()); - Response response = Response.newFixedLengthResponse(Status.TEMPORARY_REDIRECT, MIME_PLAINTEXT, "Image not found."); - response.addHeader("Location", tile.url()); - return response; - } - } - } } diff --git a/app/src/main/java/eu/quelltext/mundraub/map/handler/ErrorHandler.java b/app/src/main/java/eu/quelltext/mundraub/map/handler/ErrorHandler.java new file mode 100644 index 0000000..447d92f --- /dev/null +++ b/app/src/main/java/eu/quelltext/mundraub/map/handler/ErrorHandler.java @@ -0,0 +1,5 @@ +package eu.quelltext.mundraub.map.handler; + +public interface ErrorHandler { + void handleError(Exception e); +} diff --git a/app/src/main/java/eu/quelltext/mundraub/map/handler/PlantCollectionHandler.java b/app/src/main/java/eu/quelltext/mundraub/map/handler/PlantCollectionHandler.java new file mode 100644 index 0000000..48b523b --- /dev/null +++ b/app/src/main/java/eu/quelltext/mundraub/map/handler/PlantCollectionHandler.java @@ -0,0 +1,37 @@ +package eu.quelltext.mundraub.map.handler; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.nanohttpd.protocols.http.IHTTPSession; +import org.nanohttpd.protocols.http.response.Response; +import org.nanohttpd.protocols.http.response.Status; + +import java.io.UnsupportedEncodingException; +import java.util.List; + +import eu.quelltext.mundraub.plant.Plant; +import eu.quelltext.mundraub.plant.PlantCollection; + +public class PlantCollectionHandler extends URIHandler { + private final PlantCollection plants; + + public PlantCollectionHandler(String uri, PlantCollection plants, ErrorHandler errorHandler) { + super(uri, errorHandler); + this.plants = plants; + } + + @Override + public Response respondTo(IHTTPSession input) throws JSONException, UnsupportedEncodingException { + List plantList = plants.all(); + JSONArray json = new JSONArray(); + for (Plant plant: plantList) { + JSONObject plantJSON = plant.toJSON(); + json.put(plantJSON); + } + String string = json.toString(); + byte[] bytes = string.getBytes("UTF-8"); + Response result = Response.newFixedLengthResponse(Status.OK, "application/json", bytes); + return result; + } +} diff --git a/app/src/main/java/eu/quelltext/mundraub/map/handler/TilesHandler.java b/app/src/main/java/eu/quelltext/mundraub/map/handler/TilesHandler.java new file mode 100644 index 0000000..981f822 --- /dev/null +++ b/app/src/main/java/eu/quelltext/mundraub/map/handler/TilesHandler.java @@ -0,0 +1,50 @@ +package eu.quelltext.mundraub.map.handler; + +import org.nanohttpd.protocols.http.IHTTPSession; +import org.nanohttpd.protocols.http.NanoHTTPD; +import org.nanohttpd.protocols.http.response.Response; +import org.nanohttpd.protocols.http.response.Status; + +import eu.quelltext.mundraub.error.Logger; +import eu.quelltext.mundraub.map.MundraubMapAPIForApp; +import eu.quelltext.mundraub.map.TilesCache; + +public class TilesHandler extends URIHandler { + private final Logger.Log log; + private MundraubMapAPIForApp mundraubMapAPIForApp; + private final TilesCache cache; + + public TilesHandler(MundraubMapAPIForApp mundraubMapAPIForApp, String uri, TilesCache cache, ErrorHandler errorHandler, Logger.Log log) { + super(uri, errorHandler); + this.mundraubMapAPIForApp = mundraubMapAPIForApp; + this.cache = cache; + this.log = log; + } + + @Override + public boolean wantsToServeURI(String uri) { + return uri.startsWith(baseUri()); + } + + public Response respondTo(IHTTPSession input) throws Exception { + String[] zyx = input.getUri().substring(this.baseUri().length()).split("/"); + if (zyx.length < 3) { + return Response.newFixedLengthResponse(Status.INTERNAL_ERROR, NanoHTTPD.MIME_PLAINTEXT, "I need " + baseUri() + "z/y/x"); + } + int x = Integer.parseInt(zyx[zyx.length - 1]); + int y = Integer.parseInt(zyx[zyx.length - 2]); + int z = Integer.parseInt(zyx[zyx.length - 3]); + TilesCache.Tile tile = cache.getTileAt(x, y, z); + if (tile.isCached()) { + log.d("handle tile", 200 + ": " + z + "/" + y + "/" + x); + Response response = Response.newFixedLengthResponse(Status.OK, tile.contentType(), tile.bytes()); + response.addHeader("Cache-Control", "no-store, must-revalidate"); // no cache from https://stackoverflow.com/a/2068407 + return response; + } else { + log.d("handle tile", 307 + ": " + z + "/" + y + "/" + x + " -> " + tile.url()); + Response response = Response.newFixedLengthResponse(Status.TEMPORARY_REDIRECT, NanoHTTPD.MIME_PLAINTEXT, "Image not found."); + response.addHeader("Location", tile.url()); + return response; + } + } +} diff --git a/app/src/main/java/eu/quelltext/mundraub/map/handler/URIHandler.java b/app/src/main/java/eu/quelltext/mundraub/map/handler/URIHandler.java new file mode 100644 index 0000000..2b28f1b --- /dev/null +++ b/app/src/main/java/eu/quelltext/mundraub/map/handler/URIHandler.java @@ -0,0 +1,64 @@ +package eu.quelltext.mundraub.map.handler; + +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.nanohttpd.protocols.http.IHTTPSession; +import org.nanohttpd.protocols.http.NanoHTTPD; +import org.nanohttpd.protocols.http.request.Method; +import org.nanohttpd.protocols.http.response.Response; +import org.nanohttpd.protocols.http.response.Status; +import org.nanohttpd.util.IHandler; + +public class URIHandler implements IHandler { + + private final String uri; + private final ErrorHandler errorHandler; + + public URIHandler(String uri,ErrorHandler errorHandler) { + this.uri = uri; + this.errorHandler = errorHandler; + } + + @Override + public Response handle(IHTTPSession input) { + if (wantsToServe(input)) { + Response response; + try { + response = respondTo(input); + } catch (Exception e) { + response = handleError(e); + } + response.addHeader("Access-Control-Allow-Origin", "*"); // allow JavaScript to access the content + return response; + } + return null; + } + + // this should be overwritten + public Response respondTo(IHTTPSession input) throws Exception { + return null; + } + + public boolean wantsToServe(IHTTPSession input) { + return wantsToHandleMethod(input.getMethod()) && + wantsToServeURI(input.getUri()); + } + + public boolean wantsToServeURI(String uri) { + return uri.equals(this.uri); + } + + public boolean wantsToHandleMethod(Method method) { + return method == Method.GET; + } + + public Response handleError(Exception e) { + errorHandler.handleError(e); + String msg = "

500 Internal server error

\n" + + "
" + ExceptionUtils.getStackTrace(e) + "
"; + return Response.newFixedLengthResponse(Status.INTERNAL_ERROR, NanoHTTPD.MIME_HTML, msg); + } + + protected String baseUri() { + return uri; + } +} diff --git a/app/src/main/java/eu/quelltext/mundraub/plant/Plant.java b/app/src/main/java/eu/quelltext/mundraub/plant/Plant.java index a9c5dc2..d032aa4 100644 --- a/app/src/main/java/eu/quelltext/mundraub/plant/Plant.java +++ b/app/src/main/java/eu/quelltext/mundraub/plant/Plant.java @@ -126,7 +126,7 @@ public static void loadAll() { getPlants(); } - private static PlantCollection getPlants() { + public static PlantCollection getPlants() { if (plants == null) { plants = new PersistentPlantCollection(); }