package acme.sample.services;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.wink.json4j.JSONArray;
import org.apache.wink.json4j.JSONException;
import org.apache.wink.json4j.JSONObject;
import acme.dataapp.Flights;
import acme.dataapp.MyFlights;
/**
* Handles request regarding flights.
*
*/
public class FlightsServlet extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = 6312354232706602537L;
private static Logger log = java.util.logging.Logger.getAnonymousLogger();
private static final String FLIGHT_ID = "FlightId";
private static final String USER_ID = "UserId";
private static final String APPROVER_ID = "ApproverId";
private static final String REASON = "Reason";
private static final String STATE = "state";
/* (non-Javadoc)
* @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
/*
* Example requests
* flights/lists -> gets all flights
* flights/lists/{flightId} -> gets a flight with the given id
* flights/{userId}/lists -> gets all flights for a specific user
* flights/{userId}/lists/{flightId} -> gets a flight for a specific user
*/
String[] paths = getPaths(req.getPathInfo().toLowerCase());
if(paths[0].equalsIgnoreCase("lists")){
//requesting a specific flight or all flights
String id = (paths.length > 1) ? paths[1] : null;
getFlights(id, req, resp);
} else if(paths.length > 0 && paths[1].equalsIgnoreCase("lists")){
//Must be flights for a specific user
String userId = paths[0];
String flightId = (paths.length > 2) ? paths[2] : null;
getFlightsForUser(userId, flightId, req, resp);
} else if(paths.length > 0 && paths[1].equalsIgnoreCase("users")){
//Must be users for a specific flight
String flightId = paths[0];
getUsersForFlight(flightId, req, resp);
}
}
private String[] getPaths(String path) {
if(path.startsWith("/")) {
path = path.replaceFirst("/", "");
}
return path.split("/");
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String contentType = req.getContentType();
if(contentType == null || !contentType.startsWith("application/json")) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid Content-Type, must be application/json.");
return;
}
String[] paths = getPaths(req.getPathInfo().toLowerCase());
if(!"lists".equalsIgnoreCase(paths[0]) && paths.length > 0 && paths[1].equalsIgnoreCase("lists")){
//Must be flights for a specific user
String userId = paths[0];
String postBody = getBody(req);
try {
JSONObject flight = new JSONObject(postBody);
if(!flight.has(FLIGHT_ID) || !flight.has(APPROVER_ID)) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST,
"The POST body must have the following properties: FlightId, UserId, ApproverId");
return;
}
String flightId = flight.getString(FLIGHT_ID);
if(flightAlreadyBooked(flightId, userId)) {
resp.setStatus(HttpServletResponse.SC_NO_CONTENT);
resp.flushBuffer();
return;
}
MyFlights.getInstance().addMyFlight(flight.getString(FLIGHT_ID), userId,
flight.getString(APPROVER_ID), flight.optString(REASON));
resp.setStatus(HttpServletResponse.SC_NO_CONTENT);
resp.flushBuffer();
return;
} catch (JSONException e) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
return;
}
}
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpServlet#doPut(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
@Override
protected void doPut(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
/*
* Examples
* flights/{userid}/lists/{flightid}
*/
String contentType = req.getContentType();
if(contentType == null || !contentType.startsWith("application/json")) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid Content-Type, must be application/json.");
return;
}
String[] paths = getPaths(req.getPathInfo().toLowerCase());
if(paths.length > 1 && paths[1].equalsIgnoreCase("lists")){
String putBody = getBody(req);
String userId = paths[0];
String flightId = paths[2];
if(!flightAlreadyBooked(flightId, userId)) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "There is no flight booked for user " + userId +
" with the flight number " + flightId + ".");
return;
}
try {
MyFlights myFlights = MyFlights.getInstance();
JSONObject updatedFlight = new JSONObject(putBody);
JSONObject currentFlight = myFlights.getFlight(userId, flightId);
String approverId = updatedFlight.has(APPROVER_ID) ? updatedFlight.getString(APPROVER_ID) :
currentFlight.getString(APPROVER_ID);
String reason = updatedFlight.has(REASON) ? updatedFlight.getString(REASON) :
currentFlight.optString(REASON);
String state = updatedFlight.has(STATE) ? updatedFlight.getString(STATE) : currentFlight.getString(STATE);
JSONObject responseFlight = myFlights.updateMyFlight(userId, flightId, approverId, reason, state);
writeJsonObjectResponse(responseFlight, resp);
resp.flushBuffer();
} catch (JSONException e) {
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
return;
}
} else {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid request");
}
}
private boolean flightAlreadyBooked(String flightId, String userId) {
JSONObject myFlightsObj = MyFlights.getInstance().getMyFlights(userId);
if(myFlightsObj.has("myflights")) {
try {
JSONArray myFlights = myFlightsObj.getJSONArray("myflights");
Iterator<JSONObject> iter = myFlights.iterator();
while(iter.hasNext()) {
if(iter.next().getString(FLIGHT_ID).equals(flightId)) {
return true;
}
}
} catch (JSONException e) {
return false;
}
}
return false;
}
private void getFlights(String id, HttpServletRequest req, HttpServletResponse resp) {
final String method = "getFlights";
if(id == null) {
try {
writeJsonArrayResponse(Flights.getInstance().getFlights().getJSONArray("flights"), resp);
} catch (JSONException e) {
try {
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
} catch (IOException e1) {
log.logp(Level.SEVERE, FlightsServlet.class.getName(), method, e.getMessage(), e);
}
}
} else {
writeJsonObjectResponse(Flights.getInstance().getFlightsByID(id), resp);
}
}
private void getFlightsForUser(String userId, String flightId, HttpServletRequest req, HttpServletResponse resp) {
final String method = "getFlights";
if(flightId == null) {
try {
writeJsonArrayResponse(MyFlights.getInstance().getMyFlights(userId).getJSONArray("myflights"), resp);
} catch (JSONException e) {
try {
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
} catch (IOException e1) {
log.logp(Level.SEVERE, FlightsServlet.class.getName(), method, e.getMessage(), e);
}
}
} else {
writeJsonObjectResponse(MyFlights.getInstance().getFlight(userId, flightId), resp);
}
}
private void getUsersForFlight(String flightId, HttpServletRequest req, HttpServletResponse resp) {
writeJsonArrayResponse(MyFlights.getInstance().getUsers(flightId), resp);
}
private void writeJsonObjectResponse(JSONObject json, HttpServletResponse resp) {
final String method = "writeJsonObjectResponse";
resp.setContentType("application/json");
try {
json.write(resp.getWriter());
} catch (Exception e) {
try {
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
} catch (IOException e1) {
log.logp(Level.SEVERE, FlightsServlet.class.getName(), method, e.getMessage(), e);
}
} finally {
try {
resp.flushBuffer();
} catch (IOException e) {
log.logp(Level.SEVERE, FlightsServlet.class.getName(), method, e.getMessage(), e);
}
}
}
private void writeJsonArrayResponse(JSONArray json, HttpServletResponse resp) {
final String method = "writeJsonArrayResponse";
resp.setContentType("application/json");
try {
json.write(resp.getWriter());
} catch (Exception e) {
try {
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
} catch (IOException e1) {
log.logp(Level.SEVERE, FlightsServlet.class.getName(), method, e.getMessage(), e);
}
} finally {
try {
resp.flushBuffer();
} catch (IOException e) {
log.logp(Level.SEVERE, FlightsServlet.class.getName(), method, e.getMessage(), e);
}
}
}
private String getBody(HttpServletRequest request) throws IOException {
BufferedInputStream bis = new BufferedInputStream(request.getInputStream());
ByteArrayOutputStream buf = new ByteArrayOutputStream();
int result = bis.read();
while (result != -1) {
byte b = (byte) result;
buf.write(b);
result = bis.read();
}
buf.close();
String body = buf.toString();
return body;
}
}