package edu.pdx.cs410J.phonebillweb;
import com.google.common.annotations.VisibleForTesting;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
/**
* This servlet ultimately provides a REST API for working with an
* <code>PhoneBill</code>. However, in its current state, it is an example
* of how to use HTTP and Java servlets to store simple key/value pairs.
*/
public class PhoneBillServlet extends HttpServlet
{
private final Map<String, String> data = new HashMap<>();
/**
* Handles an HTTP GET request from a client by writing the value of the key
* specified in the "key" HTTP parameter to the HTTP response. If the "key"
* parameter is not specified, all of the key/value pairs are written to the
* HTTP response.
*/
@Override
protected void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException
{
response.setContentType( "text/plain" );
String key = getParameter( "key", request );
if (key != null) {
writeValue(key, response);
} else {
writeAllMappings(response);
}
}
/**
* Handles an HTTP POST request by storing the key/value pair specified by the
* "key" and "value" request parameters. It writes the key/value pair to the
* HTTP response.
*/
@Override
protected void doPost( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException
{
response.setContentType( "text/plain" );
String key = getParameter( "key", request );
if (key == null) {
missingRequiredParameter(response, "key");
return;
}
String value = getParameter( "value", request );
if ( value == null) {
missingRequiredParameter( response, "value" );
return;
}
this.data.put(key, value);
PrintWriter pw = response.getWriter();
pw.println(Messages.mappedKeyValue(key, value));
pw.flush();
response.setStatus( HttpServletResponse.SC_OK);
}
/**
* Handles an HTTP DELETE request by removing all key/value pairs. This
* behavior is exposed for testing purposes only. It's probably not
* something that you'd want a real application to expose.
*/
@Override
protected void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/plain");
this.data.clear();
PrintWriter pw = response.getWriter();
pw.println(Messages.allMappingsDeleted());
pw.flush();
response.setStatus(HttpServletResponse.SC_OK);
}
/**
* Writes an error message about a missing parameter to the HTTP response.
*
* The text of the error message is created by {@link Messages#missingRequiredParameter(String)}
*/
private void missingRequiredParameter( HttpServletResponse response, String parameterName )
throws IOException
{
String message = Messages.missingRequiredParameter(parameterName);
response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED, message);
}
/**
* Writes the value of the given key to the HTTP response.
*
* The text of the message is formatted with {@link Messages#getMappingCount(int)}
* and {@link Messages#formatKeyValuePair(String, String)}
*/
private void writeValue( String key, HttpServletResponse response ) throws IOException
{
String value = this.data.get(key);
PrintWriter pw = response.getWriter();
pw.println(Messages.getMappingCount( value != null ? 1 : 0 ));
pw.println(Messages.formatKeyValuePair(key, value));
pw.flush();
response.setStatus( HttpServletResponse.SC_OK );
}
/**
* Writes all of the key/value pairs to the HTTP response.
*
* The text of the message is formatted with
* {@link Messages#formatKeyValuePair(String, String)}
*/
private void writeAllMappings( HttpServletResponse response ) throws IOException
{
PrintWriter pw = response.getWriter();
pw.println(Messages.getMappingCount(data.size()));
for (Map.Entry<String, String> entry : this.data.entrySet()) {
pw.println(Messages.formatKeyValuePair(entry.getKey(), entry.getValue()));
}
pw.flush();
response.setStatus( HttpServletResponse.SC_OK );
}
/**
* Returns the value of the HTTP request parameter with the given name.
*
* @return <code>null</code> if the value of the parameter is
* <code>null</code> or is the empty string
*/
private String getParameter(String name, HttpServletRequest request) {
String value = request.getParameter(name);
if (value == null || "".equals(value)) {
return null;
} else {
return value;
}
}
@VisibleForTesting
void setValueForKey(String key, String value) {
this.data.put(key, value);
}
@VisibleForTesting
String getValueForKey(String key) {
return this.data.get(key);
}
}