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