package edu.pdx.cs410J.servlets; import edu.pdx.cs410J.rmi.Movie; import edu.pdx.cs410J.rmi.MovieDatabase; import edu.pdx.cs410J.rmi.MovieDatabaseImpl; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.BufferedReader; import java.io.IOException; import java.io.PrintWriter; import java.rmi.RemoteException; import java.util.Comparator; import java.util.HashMap; import java.util.Map; import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST; import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND; /** * A servlet that provides REST access to a movie database */ public class MovieDatabaseServlet extends HttpServlet { private MovieDatabase database; enum DataType { MOVIE, ACTOR, CHARACTER, UNKNOWN } @Override public void init() throws ServletException { try { this.database = new MovieDatabaseImpl(); } catch (RemoteException ex) { throw new ServletException(ex); } } /** * Returns the type of data requested */ private DataType getDataType(HttpServletRequest request) { String uri = request.getRequestURI(); if (uri.contains("actors")) { return DataType.ACTOR; } else if (uri.contains("characters")) { return DataType.CHARACTER; } else if (uri.contains("movies")) { return DataType.MOVIE; } else { return DataType.UNKNOWN; } } /** * Updates information in the database * * @param request The request from the client. Note that unlike POST, data * arrives in the body (conent) of the request. {#link getParameter} returns * <code>null</code> */ @Override protected void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Map<String, String> parameters = readParametersFromRequest(request); response.setContentType("text/plain"); DataType dataType = getDataType(request); switch (dataType) { case MOVIE: updateMovie(parameters, response); break; case UNKNOWN: response.sendError(SC_BAD_REQUEST, "Unknown dataType: " + dataType); break; } } private Map<String, String> readParametersFromRequest(HttpServletRequest request) throws IOException { Map<String, String> parameters = new HashMap<>(); BufferedReader br = request.getReader(); // new BufferedReader(new InputStreamReader(request.getInputStream(), Charset.forName("UTF-8"))); for (String line = br.readLine(); line != null; line = br.readLine()) { String[] strings = line.split("="); parameters.put(strings[0], strings[1]); } return parameters; } /** * Creates a new movie in the database */ private void createMovie(HttpServletRequest parameters, HttpServletResponse response) throws IOException { String title = parameters.getParameter("title"); if (notExists(title)) { response.sendError(SC_BAD_REQUEST, "Missing title"); return; } String yearString = parameters.getParameter("year"); if (notExists(yearString)) { response.sendError(SC_BAD_REQUEST, "Missing year"); return; } int year; try { year = Integer.parseInt(yearString); } catch (NumberFormatException ex) { response.sendError(SC_BAD_REQUEST, "Malformed year: " + yearString); return; } long movieId = this.database.createMovie(title, year); PrintWriter pw = response.getWriter(); pw.println(movieId); } /** * Returns whether or not the given parameter value was specified * @return <code>true</code> if <code>value</code> is <code>null</code> or * the empty string */ private boolean notExists(String value) { return value == null || value.equals(""); } /** * Searches for information in the database */ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/plain"); switch (getDataType(request)) { case MOVIE: dumpMovies(request, response); } } /** * Creates information in the database */ @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/plain"); switch (getDataType(request)) { case MOVIE: createMovie(request, response); } } private void updateMovie(Map<String, String> request, HttpServletResponse response) throws IOException { // System.out.println(request.getParameterMap().size() + " parameters"); // for (Object key : request.getParameterMap().keySet()) { // String value = request.getParameter((String) key); // System.out.println(" " + key + " -> " + value); // } String idString = request.get("id"); if (notExists(idString)) { response.sendError(SC_BAD_REQUEST, "Missing id"); return; } Movie movie; try { movie = this.database.getMovie(Long.parseLong(idString)); } catch (NumberFormatException ex) { response.sendError(SC_BAD_REQUEST, "Malformed id: " + idString); return; } if (movie == null) { response.sendError(SC_BAD_REQUEST, "Unknown movie: " + idString); return; } String title = request.get("title"); if (title != null) { movie.setTitle(title); } String yearString = request.get("year"); if (yearString != null) { try { movie.setYear(Integer.parseInt(yearString)); response.getWriter().println(idString); } catch (NumberFormatException ex) { response.sendError(SC_BAD_REQUEST, "Malformed year: " + yearString); } } } /** * Writes a description of one or more movies back to the client */ private void dumpMovies(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Comparator<Movie> sorter = (m1, m2) -> { long id1 = m1.getId(); long id2 = m2.getId(); return id1 > id2 ? 1 : id1 < id2 ? -1 : 0; }; String idString = request.getParameter("id"); try { if (notExists(idString)) { PrintWriter pw = response.getWriter(); final String title = request.getParameter("title"); final String year = request.getParameter("year"); if (notExists(title) && notExists(year)) { // Dump all movies for (Movie movie : this.database.getMovies()) { dumpMovie(movie, pw); } } else { for (Movie movie: this.database.executeQuery(movie1 -> { if (notExists(title)) { return movie1.getYear() == Integer.parseInt(year); } else if (notExists(year)) { return movie1.getTitle().contains(title); } else { return movie1.getYear() == Integer.parseInt(year) && movie1.getTitle().contains(title); } }, sorter)) { dumpMovie(movie, pw); } } } else { try { Movie movie = this.database.getMovie(Long.parseLong(idString)); if (movie == null) { response.sendError(SC_NOT_FOUND, "There is no movie with id " + idString); } else { dumpMovie(movie, response.getWriter()); } } catch (NumberFormatException ex) { response.sendError(SC_BAD_REQUEST, "Invalid movie id: " + idString); } } } catch (RemoteException ex) { throw new ServletException(ex); } } /** * Writes a description of a movie back to the client */ private void dumpMovie(Movie movie, PrintWriter pw) { pw.println(movie.getId() + " \"" + movie.getTitle() + "\" (" + movie.getYear() + ")"); } /** * Removes information from the database */ @Override protected void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Map<String, String> parameters = readParametersFromRequest(request); response.setContentType("text/plain"); DataType dataType = getDataType(request); switch (dataType) { case MOVIE: deleteMovie(parameters, response); break; case UNKNOWN: response.sendError(SC_BAD_REQUEST, "Unknown dataType: " + dataType); break; } } private void deleteMovie(Map<String, String> request, HttpServletResponse response) throws IOException { String idString = request.get("id"); if (notExists(idString)) { response.sendError(SC_BAD_REQUEST, "Missing id"); return; } Movie movie; try { movie = this.database.getMovie(Long.parseLong(idString)); } catch (NumberFormatException ex) { response.sendError(SC_BAD_REQUEST, "Malformed id: " + idString); return; } if (movie == null) { response.sendError(SC_NOT_FOUND, "Unknown movie: " + idString); return; } this.database.deleteMovie(movie.getId()); } }