001package edu.pdx.cs410J.airlineweb;
002
003import com.google.common.annotations.VisibleForTesting;
004
005import javax.servlet.http.HttpServlet;
006import javax.servlet.http.HttpServletRequest;
007import javax.servlet.http.HttpServletResponse;
008import java.io.IOException;
009import java.io.PrintWriter;
010import java.util.HashMap;
011import java.util.Map;
012
013/**
014 * This servlet ultimately provides a REST API for working with an
015 * <code>Airline</code>.  However, in its current state, it is an example
016 * of how to use HTTP and Java servlets to store simple dictionary of words
017 * and their definitions.
018 */
019public class AirlineServlet extends HttpServlet {
020  static final String WORD_PARAMETER = "word";
021  static final String DEFINITION_PARAMETER = "definition";
022
023  private final Map<String, String> dictionary = new HashMap<>();
024
025  /**
026   * Handles an HTTP GET request from a client by writing the definition of the
027   * word specified in the "word" HTTP parameter to the HTTP response.  If the
028   * "word" parameter is not specified, all of the entries in the dictionary
029   * are written to the HTTP response.
030   */
031  @Override
032  protected void doGet( HttpServletRequest request, HttpServletResponse response ) throws IOException
033  {
034      response.setContentType( "text/plain" );
035
036      String word = getParameter( WORD_PARAMETER, request );
037      if (word != null) {
038          writeDefinition(word, response);
039
040      } else {
041          writeAllDictionaryEntries(response);
042      }
043  }
044
045  /**
046   * Handles an HTTP POST request by storing the dictionary entry for the
047   * "word" and "definition" request parameters.  It writes the dictionary
048   * entry to the HTTP response.
049   */
050  @Override
051  protected void doPost( HttpServletRequest request, HttpServletResponse response ) throws IOException
052  {
053      response.setContentType( "text/plain" );
054
055      String word = getParameter(WORD_PARAMETER, request );
056      if (word == null) {
057          missingRequiredParameter(response, WORD_PARAMETER);
058          return;
059      }
060
061      String definition = getParameter(DEFINITION_PARAMETER, request );
062      if ( definition == null) {
063          missingRequiredParameter( response, DEFINITION_PARAMETER );
064          return;
065      }
066
067      this.dictionary.put(word, definition);
068
069      PrintWriter pw = response.getWriter();
070      pw.println(Messages.definedWordAs(word, definition));
071      pw.flush();
072
073      response.setStatus( HttpServletResponse.SC_OK);
074  }
075
076  /**
077   * Handles an HTTP DELETE request by removing all dictionary entries.  This
078   * behavior is exposed for testing purposes only.  It's probably not
079   * something that you'd want a real application to expose.
080   */
081  @Override
082  protected void doDelete(HttpServletRequest request, HttpServletResponse response) throws IOException {
083      response.setContentType("text/plain");
084
085      this.dictionary.clear();
086
087      PrintWriter pw = response.getWriter();
088      pw.println(Messages.allDictionaryEntriesDeleted());
089      pw.flush();
090
091      response.setStatus(HttpServletResponse.SC_OK);
092
093  }
094
095  /**
096   * Writes an error message about a missing parameter to the HTTP response.
097   *
098   * The text of the error message is created by {@link Messages#missingRequiredParameter(String)}
099   */
100  private void missingRequiredParameter( HttpServletResponse response, String parameterName )
101      throws IOException
102  {
103      String message = Messages.missingRequiredParameter(parameterName);
104      response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED, message);
105  }
106
107  /**
108   * Writes the definition of the given word to the HTTP response.
109   *
110   * The text of the message is formatted with {@link TextDumper}
111   */
112  private void writeDefinition(String word, HttpServletResponse response) throws IOException {
113    String definition = this.dictionary.get(word);
114
115    if (definition == null) {
116      response.setStatus(HttpServletResponse.SC_NOT_FOUND);
117
118    } else {
119      PrintWriter pw = response.getWriter();
120
121      Map<String, String> wordDefinition = Map.of(word, definition);
122      TextDumper dumper = new TextDumper(pw);
123      dumper.dump(wordDefinition);
124
125      response.setStatus(HttpServletResponse.SC_OK);
126    }
127  }
128
129  /**
130   * Writes all of the dictionary entries to the HTTP response.
131   *
132   * The text of the message is formatted with {@link TextDumper}
133   */
134  private void writeAllDictionaryEntries(HttpServletResponse response ) throws IOException
135  {
136      PrintWriter pw = response.getWriter();
137      TextDumper dumper = new TextDumper(pw);
138      dumper.dump(dictionary);
139
140      response.setStatus( HttpServletResponse.SC_OK );
141  }
142
143  /**
144   * Returns the value of the HTTP request parameter with the given name.
145   *
146   * @return <code>null</code> if the value of the parameter is
147   *         <code>null</code> or is the empty string
148   */
149  private String getParameter(String name, HttpServletRequest request) {
150    String value = request.getParameter(name);
151    if (value == null || "".equals(value)) {
152      return null;
153
154    } else {
155      return value;
156    }
157  }
158
159  @VisibleForTesting
160  String getDefinition(String word) {
161      return this.dictionary.get(word);
162  }
163}