package org.opentripplanner.api;
import java.util.Map;
import org.glassfish.grizzly.http.server.HttpHandler;
import org.glassfish.grizzly.http.server.Request;
import org.glassfish.grizzly.http.server.Response;
import org.onebusaway.gtfs.model.Route;
import org.opentripplanner.api.model.AgencyAndIdSerializer;
import org.opentripplanner.routing.edgetype.TransitBoardAlight;
import org.opentripplanner.routing.graph.Graph;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
/**
* This file contains experimental classes demonstrating how to avoid using Jersey.
* It would work well with ReflectiveQueryScraper.
* Of course then the API docs would have to be maintained manually.
* @author abyrd
*/
public class OTPHttpHandler extends HttpHandler {
private final ObjectMapper xmlMapper = new XmlMapper();
private final ObjectMapper jsonMapper = new ObjectMapper();
private final Map <String, OTPHandler> handlers = Maps.newHashMap();
private final Graph graph;
public OTPHttpHandler (Graph graph) {
this.graph = graph;
handlers.put("routes", new RoutesHandler());
handlers.put("plan", new PlanHandler());
Module module = AgencyAndIdSerializer.makeModule();
xmlMapper.registerModule(module);
jsonMapper.registerModule(module);
}
@Override
public void service(Request req, Response resp) throws Exception {
try {
OTPRequest oreq = new OTPRequest(req, graph);
Object result = handlers.get(oreq.action).handle(oreq);
ObjectMapper mapper;
if (oreq.sfmt == SerializeFormat.XML) {
resp.setContentType("application/xml");
mapper = xmlMapper;
} else {
resp.setContentType("application/json");
mapper = jsonMapper;
}
resp.setStatus(200);
mapper.writeValue(resp.getNIOOutputStream(), result);
} catch (Exception ex) {
resp.setStatus(500);
resp.setContentType("text/plain");
resp.getNIOWriter().write("Error: " + ex.toString());
}
}
}
interface OTPHandler { public Object handle (OTPRequest oreq); }
class RoutesHandler implements OTPHandler {
@Override
public Object handle (OTPRequest oreq) {
Map<String, Route> routes = Maps.newHashMap();
for (TransitBoardAlight ba : Iterables.filter(oreq.graph.getEdges(), TransitBoardAlight.class)) {
Route route = ba.getPattern().route;
routes.put(route.getId().toString(), route);
}
if (oreq.id != null) {
return routes.get(oreq.id);
} else {
return routes;
}
}
}
class PlanHandler implements OTPHandler {
@Override
public Object handle (OTPRequest oreq) {
return oreq.params;
}
}
enum SerializeFormat { XML, JSON }
class OTPRequest {
Graph graph;
String[] parts;
String action;
String id;
SerializeFormat sfmt;
Map<String,String> params = Maps.newHashMap();
public OTPRequest (Request req, Graph graph) {
this.graph = graph;
for (String key : req.getParameterNames()) {
params.put(key, req.getParameter(key));
}
String path = req.getPathInfo();
sfmt = SerializeFormat.JSON;
if (req.getHeader("Accept").contains("application/xml")) {
sfmt = SerializeFormat.XML;
}
if (req.getHeader("Accept").contains("application/json")) {
sfmt = SerializeFormat.JSON;
}
if (path.endsWith(".xml")) {
path = path.substring(0, path.length() - 4);
sfmt = SerializeFormat.XML;
};
if (path.endsWith(".json")) {
path = path.substring(0, path.length() - 5);
sfmt = SerializeFormat.JSON;
};
parts = path.split("/");
// path always begins with a slash, so part 0 is empty
if (parts.length > 1) action = parts[1];
if (parts.length > 2) id = parts[2];
}
}