Skip to content

Commit

Permalink
refactor local web server handler class
Browse files Browse the repository at this point in the history
- create handler package
- add handler for own plants
- contributes to #81
  • Loading branch information
niccokunzmann committed Sep 3, 2019
1 parent 23b4759 commit 9259921
Show file tree
Hide file tree
Showing 7 changed files with 172 additions and 102 deletions.
67 changes: 7 additions & 60 deletions app/src/main/java/eu/quelltext/mundraub/map/MundraubMapAPI.java
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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";
Expand Down Expand Up @@ -69,62 +68,10 @@ public Response serve(IHTTPSession session) {
return Response.newFixedLengthResponse(Status.NOT_FOUND, NanoHTTPD.MIME_HTML, msg);
}

protected class URIHandler implements IHandler<IHTTPSession, Response> {

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 = "<html><body><h1>500 Internal server errir</h1>\n" +
"<pre>" + ExceptionUtils.getStackTrace(e) + "</pre></body></html>";
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 {
Expand All @@ -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();
}

Expand Down Expand Up @@ -175,7 +122,7 @@ protected OkHttpClient client() {
protected class TranslationsHandler extends URIHandler {

public TranslationsHandler(String uri) {
super(uri);
super(uri, MundraubMapAPI.this);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,34 @@

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;

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);
}

Expand Down Expand Up @@ -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;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package eu.quelltext.mundraub.map.handler;

public interface ErrorHandler {
void handleError(Exception e);
}
Original file line number Diff line number Diff line change
@@ -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<Plant> 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;
}
}
Original file line number Diff line number Diff line change
@@ -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;
}
}
}
Original file line number Diff line number Diff line change
@@ -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<IHTTPSession, Response> {

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 = "<html><body><h1>500 Internal server error</h1>\n" +
"<pre>" + ExceptionUtils.getStackTrace(e) + "</pre></body></html>";
return Response.newFixedLengthResponse(Status.INTERNAL_ERROR, NanoHTTPD.MIME_HTML, msg);
}

protected String baseUri() {
return uri;
}
}
2 changes: 1 addition & 1 deletion app/src/main/java/eu/quelltext/mundraub/plant/Plant.java
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ public static void loadAll() {
getPlants();
}

private static PlantCollection getPlants() {
public static PlantCollection getPlants() {
if (plants == null) {
plants = new PersistentPlantCollection();
}
Expand Down

0 comments on commit 9259921

Please sign in to comment.