001package edu.pdx.cs.joy.airlineweb; 002 003import com.google.common.annotations.VisibleForTesting; 004 005import jakarta.servlet.http.HttpServlet; 006import jakarta.servlet.http.HttpServletRequest; 007import jakarta.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 log("GET " + word); 039 writeDefinition(word, response); 040 041 } else { 042 log("GET all dictionary entries"); 043 writeAllDictionaryEntries(response); 044 } 045 } 046 047 /** 048 * Handles an HTTP POST request by storing the dictionary entry for the 049 * "word" and "definition" request parameters. It writes the dictionary 050 * entry to the HTTP response. 051 */ 052 @Override 053 protected void doPost( HttpServletRequest request, HttpServletResponse response ) throws IOException 054 { 055 response.setContentType( "text/plain" ); 056 057 String word = getParameter(WORD_PARAMETER, request ); 058 if (word == null) { 059 missingRequiredParameter(response, WORD_PARAMETER); 060 return; 061 } 062 063 String definition = getParameter(DEFINITION_PARAMETER, request ); 064 if ( definition == null) { 065 missingRequiredParameter( response, DEFINITION_PARAMETER ); 066 return; 067 } 068 069 log("POST " + word + " -> " + definition); 070 071 this.dictionary.put(word, definition); 072 073 PrintWriter pw = response.getWriter(); 074 pw.println(Messages.definedWordAs(word, definition)); 075 pw.flush(); 076 077 response.setStatus( HttpServletResponse.SC_OK); 078 } 079 080 /** 081 * Handles an HTTP DELETE request by removing all dictionary entries. This 082 * behavior is exposed for testing purposes only. It's probably not 083 * something that you'd want a real application to expose. 084 */ 085 @Override 086 protected void doDelete(HttpServletRequest request, HttpServletResponse response) throws IOException { 087 response.setContentType("text/plain"); 088 089 log("DELETE all dictionary entries"); 090 091 this.dictionary.clear(); 092 093 PrintWriter pw = response.getWriter(); 094 pw.println(Messages.allDictionaryEntriesDeleted()); 095 pw.flush(); 096 097 response.setStatus(HttpServletResponse.SC_OK); 098 099 } 100 101 /** 102 * Writes an error message about a missing parameter to the HTTP response. 103 * 104 * The text of the error message is created by {@link Messages#missingRequiredParameter(String)} 105 */ 106 private void missingRequiredParameter( HttpServletResponse response, String parameterName ) 107 throws IOException 108 { 109 String message = Messages.missingRequiredParameter(parameterName); 110 response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED, message); 111 } 112 113 /** 114 * Writes the definition of the given word to the HTTP response. 115 * 116 * The text of the message is formatted with {@link TextDumper} 117 */ 118 private void writeDefinition(String word, HttpServletResponse response) throws IOException { 119 String definition = this.dictionary.get(word); 120 121 if (definition == null) { 122 response.setStatus(HttpServletResponse.SC_NOT_FOUND); 123 124 } else { 125 PrintWriter pw = response.getWriter(); 126 127 Map<String, String> wordDefinition = Map.of(word, definition); 128 TextDumper dumper = new TextDumper(pw); 129 dumper.dump(wordDefinition); 130 131 response.setStatus(HttpServletResponse.SC_OK); 132 } 133 } 134 135 /** 136 * Writes all of the dictionary entries to the HTTP response. 137 * 138 * The text of the message is formatted with {@link TextDumper} 139 */ 140 private void writeAllDictionaryEntries(HttpServletResponse response ) throws IOException 141 { 142 PrintWriter pw = response.getWriter(); 143 TextDumper dumper = new TextDumper(pw); 144 dumper.dump(dictionary); 145 146 response.setStatus( HttpServletResponse.SC_OK ); 147 } 148 149 /** 150 * Returns the value of the HTTP request parameter with the given name. 151 * 152 * @return <code>null</code> if the value of the parameter is 153 * <code>null</code> or is the empty string 154 */ 155 private String getParameter(String name, HttpServletRequest request) { 156 String value = request.getParameter(name); 157 if (value == null || "".equals(value)) { 158 return null; 159 160 } else { 161 return value; 162 } 163 } 164 165 @VisibleForTesting 166 String getDefinition(String word) { 167 return this.dictionary.get(word); 168 } 169 170 @Override 171 public void log(String msg) { 172 System.out.println(msg); 173 } 174}