/* This program is free software: you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package org.opentripplanner.api.ws;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriInfo;
import javax.xml.bind.annotation.XmlRootElement;
import lombok.Setter;
import org.codehaus.jettison.json.JSONException;
import org.opentripplanner.api.common.RoutingResource;
import org.opentripplanner.api.model.TripPlan;
import org.opentripplanner.api.model.error.PlannerError;
import org.opentripplanner.routing.core.RoutingRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sun.jersey.api.core.InjectParam;
import com.sun.jersey.api.spring.Autowire;
/**
* This is the primary entry point for the trip planning web service.
* All parameters are passed in the query string. These parameters are defined in the abstract
* SearchResource superclass, which also has methods for building routing requests from query
* parameters. In order for inheritance to work, the REST resources are actually request-scoped
* rather than singleton-scoped.
*
* Some parameters may not be honored by the trip planner for some or all itineraries. For
* example, maxWalkDistance may be relaxed if the alternative is to not provide a route.
*
* @return Returns either an XML or a JSON document, depending on the HTTP Accept header of the
* client making the request.
*
* @throws JSONException
*/
@Path("/plan") // NOTE - /ws/plan is the full path. The prefix is added by the servlet's web.xml.
@XmlRootElement
@Autowire
public class Planner extends RoutingResource {
private static final Logger LOG = LoggerFactory.getLogger(Planner.class);
@Setter @InjectParam
public PlanGenerator planGenerator;
// We inject info about the incoming request so we can include the incoming query
// parameters in the outgoing response. This is a TriMet requirement.
// Jersey seems to use @Context to inject internal types and @InjectParam or @Resource for DI objects.
@Context UriInfo uriInfo;
/** Java is immensely painful. TODO: Guava should cover this. */
interface OneArgFunc<T,U> {
public T call(U arg);
}
private Response wrapGenerate(OneArgFunc<TripPlan, RoutingRequest> func) {
/*
* TODO: add Lang / Locale parameter, and thus get localized content (Messages & more...)
* TODO: from/to inputs should be converted / geocoded / etc... here, and maybe send coords
* or vertex ids to planner (or error back to user)
* TODO: org.opentripplanner.routing.impl.PathServiceImpl has COOORD parsing. Abstract that
* out so it's used here too...
*/
// create response object, containing a copy of all request parameters
Response response = new Response(uriInfo);
RoutingRequest request = null;
try {
// fill in request from query parameters via shared superclass method
request = super.buildRequest();
TripPlan plan = func.call(request);
response.setPlan(plan);
} catch (Exception e) {
PlannerError error = new PlannerError(e);
e.printStackTrace();
response.setError(error);
} finally {
if (request != null)
request.cleanup();
}
return response;
}
@GET
@Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML })
public Response getItineraries() throws JSONException {
return wrapGenerate(new OneArgFunc<TripPlan, RoutingRequest>() {
public TripPlan call(RoutingRequest request) {
return planGenerator.generate(request);
}});
}
@GET
@Path("/first")
@Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML })
public Response getFirstTrip() throws JSONException {
return wrapGenerate(new OneArgFunc<TripPlan, RoutingRequest>() {
public TripPlan call(RoutingRequest request) {
return planGenerator.generateFirstTrip(request);
}});
}
@GET
@Path("/last")
@Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML })
public Response getLastTrip() throws JSONException {
return wrapGenerate(new OneArgFunc<TripPlan, RoutingRequest>() {
public TripPlan call(RoutingRequest request) {
return planGenerator.generateLastTrip(request);
}});
}
}