You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pivot.apache.org by gb...@apache.org on 2010/01/29 22:44:53 UTC
svn commit: r904637 - in /pivot/trunk:
web-server/src/org/apache/pivot/web/server/ web/src/org/apache/pivot/web/
web/test/org/apache/pivot/web/test/
Author: gbrown
Date: Fri Jan 29 21:44:52 2010
New Revision: 904637
URL: http://svn.apache.org/viewvc?rev=904637&view=rev
Log:
Add caseSensitiveKeys flag to QueryDictionary (HTTP headers are not case-sensitive); update QueryServlet API for consistency with Query API.
Removed:
pivot/trunk/web-server/src/org/apache/pivot/web/server/ClientException.java
Modified:
pivot/trunk/web-server/src/org/apache/pivot/web/server/QueryServlet.java
pivot/trunk/web/src/org/apache/pivot/web/Query.java
pivot/trunk/web/src/org/apache/pivot/web/QueryDictionary.java
pivot/trunk/web/test/org/apache/pivot/web/test/QueryDictionaryTest.java
Modified: pivot/trunk/web-server/src/org/apache/pivot/web/server/QueryServlet.java
URL: http://svn.apache.org/viewvc/pivot/trunk/web-server/src/org/apache/pivot/web/server/QueryServlet.java?rev=904637&r1=904636&r2=904637&view=diff
==============================================================================
--- pivot/trunk/web-server/src/org/apache/pivot/web/server/QueryServlet.java (original)
+++ pivot/trunk/web-server/src/org/apache/pivot/web/server/QueryServlet.java Fri Jan 29 21:44:52 2010
@@ -26,140 +26,62 @@
import java.net.URLDecoder;
import java.util.Enumeration;
-import javax.security.auth.login.LoginException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import org.apache.pivot.collections.HashMap;
+import org.apache.pivot.serialization.CSVSerializer;
+import org.apache.pivot.serialization.JSONSerializer;
import org.apache.pivot.serialization.SerializationException;
import org.apache.pivot.serialization.Serializer;
-import org.apache.pivot.util.Base64;
+import org.apache.pivot.web.Query;
import org.apache.pivot.web.QueryDictionary;
+import org.apache.pivot.web.QueryException;
/**
- * Abstract base class for web query servlets. It is the server counterpart to
- * {@link org.apache.pivot.web.Query}.
+ * Abstract base class for query servlets.
*/
public abstract class QueryServlet extends HttpServlet {
- static final long serialVersionUID = -646654620936816287L;
+ private static final long serialVersionUID = 0;
- /**
- * Supported HTTP methods.
- */
- public enum Method {
- GET,
- POST,
- PUT,
- DELETE;
- }
-
- /**
- * User credentials, which will be made availale if the servlet's
- * <tt>authenticationRequired</tt> flag is set to <tt>true</tt>.
- */
- public static final class Credentials {
- private String username;
- private String password;
-
- private Credentials(String username, String password) {
- this.username = username;
- this.password = password;
- }
-
- public String getUsername() {
- return username;
- }
-
- public String getPassword() {
- return password;
- }
- }
-
- private boolean authenticationRequired = false;
private boolean determineContentLength = false;
-
- private transient ThreadLocal<Credentials> credentials = new ThreadLocal<Credentials>();
+ private HashMap<String, Class<? extends Serializer<?>>> serializerTypes
+ = new HashMap<String, Class<? extends Serializer<?>>>();
private transient ThreadLocal<String> hostname = new ThreadLocal<String>();
- private transient ThreadLocal<String> contextPath = new ThreadLocal<String>();
- private transient ThreadLocal<String> queryPath = new ThreadLocal<String>();
private transient ThreadLocal<Integer> port = new ThreadLocal<Integer>();
+ private transient ThreadLocal<String> servletPath = new ThreadLocal<String>();
private transient ThreadLocal<Boolean> secure = new ThreadLocal<Boolean>();
- private transient ThreadLocal<Method> method = new ThreadLocal<Method>();
private transient ThreadLocal<QueryDictionary> parameters = new ThreadLocal<QueryDictionary>();
private transient ThreadLocal<QueryDictionary> requestHeaders = new ThreadLocal<QueryDictionary>();
private transient ThreadLocal<QueryDictionary> responseHeaders = new ThreadLocal<QueryDictionary>();
- private static final String BASIC_AUTHENTICATION_TAG = "Basic";
- private static final String HTTP_PROTOCOL = "http";
- private static final String HTTPS_PROTOCOL = "https";
- private static final String URL_ENCODING = "UTF-8";
+ public static final String HTTP_PROTOCOL = "http";
+ public static final String HTTPS_PROTOCOL = "https";
+ public static final String URL_ENCODING = "UTF-8";
+
+ public static final String ACTION_HEADER = "Action";
+ public static final String CONTENT_TYPE_HEADER = "Content-Type";
+ public static final String CONTENT_LENGTH_HEADER = "Content-Length";
+ public static final String LOCATION_HEADER = "Location";
- /**
- * Tells whether this servlet is configured to always determine the content
- * length of outgoing responses and set the <tt>Content-Length</tt> HTTP
- * response header accordingly. If this flag is <tt>false</tt>, it is up to
- * the servlet's discretion as to when to set the <tt>Content-Length</tt>
- * header (it will do so if it is trivially easy). If this is set to
- * <tt>true</tt>, it will force the servlet to always set the header, but
- * doing so will incur a performance penalty, as the servlet will be unable
- * to stream the response directly to the HTTP output stream as it gets
- * serialized.
- */
- public boolean isDetermineContentLength() {
- return determineContentLength;
- }
-
- /**
- * Sets the value of the <tt>determineContentLength</tt> flag.
- *
- * @see #isDetermineContentLength()
- */
- public void setDetermineContentLength(boolean determineContentLength) {
- this.determineContentLength = determineContentLength;
- }
+ @Override
+ public void init() throws ServletException {
+ super.init();
- /**
- * Tells whether or not this servlet will require authentication data. If
- * set to <tt>true</tt>, and un-authenticated requests are received, the
- * servlet will automatically respond with a request for authentication.
- */
- public boolean isAuthenticationRequired() {
- return authenticationRequired;
- }
+ // TODO Read determineContentLength and MIME type-serializer class mapping
+ // from init params
- /**
- * Sets whether or not this servlet will require authentication data. If
- * set to <tt>true</tt>, and un-authenticated requests are received, the
- * servlet will automatically respond with a request for authentication.
- */
- public void setAuthenticationRequired(boolean authenticationRequired) {
- this.authenticationRequired = authenticationRequired;
+ serializerTypes.put(JSONSerializer.MIME_TYPE, JSONSerializer.class);
+ serializerTypes.put(CSVSerializer.MIME_TYPE, CSVSerializer.class);
- if (!authenticationRequired) {
- credentials.remove();
- }
+ System.out.println(serializerTypes);
}
/**
- * Creates a new serializer capable of serializing the objects that this
- * servlet reads and writes. For <tt>GET</tt> requests, this serializer
- * will be used to write the response back to the client. For <tt>PUT</tt>
- * and <tt>POST</tt> requests, this serializer will be used to read the
- * object passed by the client.
- * <p>
- * <b>Note</b>: Since this servlet may be accessed by multiple threads,
- * subclasses should <b>not</b> re-use servlets unless they do so in a
- * thread-safe manner.
- *
- * @return
- * A new serializer
- */
- protected abstract Serializer<?> newSerializer();
-
- /**
* Gets the host name that was requested.
*/
public String getHostname() {
@@ -167,26 +89,6 @@
}
/**
- * Returns the portion of the request URI that indicates the context of the
- * request. The context path always comes first in a request URI. The path
- * starts with a "/" character but does not end with a "/" character. For
- * servlets in the default (root) context, this method returns "".
- */
- public String getContextPath() {
- return contextPath.get();
- }
-
- /**
- * Returns the portion of the request URI that occurs after the context
- * path but preceding the query string. It will start with a "/" character.
- * For servlets in the default (root) context, this method returns the full
- * path.
- */
- public String getQueryPath() {
- return queryPath.get();
- }
-
- /**
* Returns the Internet Protocol (IP) port number of the interface on which
* the request was received.
*/
@@ -195,6 +97,13 @@
}
/**
+ * Returns the portion of the request URL representing the servlet path.
+ */
+ public String getServletPath() {
+ return servletPath.get();
+ }
+
+ /**
* Tells whether the request has been ecrypted over HTTPS.
*/
public boolean isSecure() {
@@ -209,22 +118,6 @@
}
/**
- * Gets the HTTP method with which the current request was made.
- */
- public Method getMethod() {
- return method.get();
- }
-
- /**
- * Gets the authentication credentials that were extracted from the
- * request. These are only available if the <tt>authenticationRequired</tt>
- * flag is set to <tt>true</tt>.
- */
- public Credentials getCredentials() {
- return credentials.get();
- }
-
- /**
* Returns the servlet's parameter dictionary, which holds the values
* passed in the HTTP request query string.
*/
@@ -249,151 +142,72 @@
}
/**
- * Called when an HTTP GET is received. This base method throws
- * <tt>UnsupportedOperationException</tt>, which will cause an HTTP 405
- * (method not allowed) to be sent in the response. Subclasses should
- * override this method if they wish to support GET requests.
- * <p>
- * Request parameters, and request/response headers are available to
- * subclasses via the corresponding query dictionary.
- *
- * @return
- * The object that was retrieved via the GET request. This object will be
- * serialized by this servlet's serializer before being included in the
- * HTTP response
- *
- * @throws ServletException
- * If the server encounters an error while processing the request.
+ * Handles an HTTP GET request. The default implementation throws an HTTP
+ * 405 query exception.
*
- * @throws ClientException
- * If the client request is invalid in any way. This will cause the client
- * to receive an HTTP 400 (bad request) response.
+ * @param path
*
- * @throws UnsupportedOperationException
- * If HTTP <tt>GET</tt> is not supported by the servlet.
+ * @return
+ * The result of the GET.
*
- * @see #getParameters()
- * @see #getRequestHeaders()
- * @see #getResponseHeaders()
+ * @throws QueryException
*/
- protected Object doGet() throws ServletException, ClientException {
- throw new UnsupportedOperationException();
+ public Object doGet(String path) throws QueryException {
+ throw new QueryException(Query.Status.METHOD_NOT_ALLOWED);
}
/**
- * Called when an HTTP POST is received. This base method throws
- * <tt>UnsupportedOperationException</tt>, which will cause an HTTP 405
- * (method not allowed) to be sent in the response. Subclasses should
- * override this method if they wish to support POST requests.
- * <p>
- * Request parameters, and request/response headers are available to
- * subclasses via the corresponding query dictionary.
+ * Handles an HTTP POST request. The default implementation throws an HTTP
+ * 405 query exception.
*
+ * @param path
* @param value
- * The object that is being posted by the client. This object will have
- * been de-serialized from within the request by this servlet's serializer
*
* @return
- * The URL identifying the location of the object that was posted. The
- * semantics of this URL are up to the subclass to define
- *
- * @throws ServletException
- * If the server encounters an error while processing the request.
- *
- * @throws ClientException
- * If the client request is invalid in any way. This will cause the client
- * to receive an HTTP 400 (bad request) response.
- *
- * @throws UnsupportedOperationException
- * If HTTP <tt>POST</tt> is not supported by the servlet.
+ * A URL containing the location of the created resource.
*
- * @see #getParameters()
- * @see #getRequestHeaders()
- * @see #getResponseHeaders()
+ * @throws QueryException
*/
- protected URL doPost(Object value) throws ServletException, ClientException {
- throw new UnsupportedOperationException();
+ public URL doPost(String path, Object value) throws QueryException {
+ throw new QueryException(Query.Status.METHOD_NOT_ALLOWED);
}
/**
- * Called when an HTTP PUT is received. This base method throws
- * <tt>UnsupportedOperationException</tt>, which will cause an HTTP 405
- * (method not allowed) to be sent in the response. Subclasses should
- * override this method if they wish to support PUT requests.
- * <p>
- * Request parameters, and request/response headers are available to
- * subclasses via the corresponding query dictionary.
- *
- * @param value
- * The object that is being updated by the client. This object will have
- * been de-serialized from within the request by this servlet's serializer
- *
- * @throws ServletException
- * If the server encounters an error while processing the request.
- *
- * @throws ClientException
- * If the client request is invalid in any way. This will cause the client
- * to receive an HTTP 400 (bad request) response.
+ * Handles an HTTP POST/Action request. The default implementation throws an HTTP
+ * 405 query exception.
*
- * @throws UnsupportedOperationException
- * If HTTP <tt>PUT</tt> is not supported by the servlet.
+ * @param path
+ * @param action
*
- * @see #getParameters()
- * @see #getRequestHeaders()
- * @see #getResponseHeaders()
+ * @throws QueryException
*/
- protected void doPut(Object value) throws ServletException, ClientException {
- throw new UnsupportedOperationException();
+ public void doPostAction(String path, String action) throws QueryException {
+ throw new QueryException(Query.Status.METHOD_NOT_ALLOWED);
}
/**
- * Called when an HTTP DELETE is received. This base method throws
- * <tt>UnsupportedOperationException</tt>, which will cause an HTTP 405
- * (method not allowed) to be sent in the response. Subclasses should
- * override this method if they wish to support DELETE requests.
- * <p>
- * Request parameters, and request/response headers are available to
- * subclasses via the corresponding query dictionary.
+ * Handles an HTTP GET request. The default implementation throws an HTTP
+ * 405 query exception.
*
- * @throws ServletException
- * If the server encounters an error while processing the request.
- *
- * @throws ClientException
- * If the client request is invalid in any way. This will cause the client
- * to receive an HTTP 400 (bad request) response.
- *
- * @throws UnsupportedOperationException
- * If HTTP <tt>DELETE</tt> is not supported by the servlet.
+ * @param path
+ * @param value
*
- * @see #getParameters()
- * @see #getRequestHeaders()
- * @see #getResponseHeaders()
+ * @throws QueryException
*/
- protected void doDelete() throws ServletException, ClientException {
- throw new UnsupportedOperationException();
+ public void doPut(String path, Object value) throws QueryException {
+ throw new QueryException(Query.Status.METHOD_NOT_ALLOWED);
}
/**
- * Authorizes the current request, and throws a <tt>LoginException</tt> if
- * the request is not authorized. This method will only be called if the
- * <tt>authenticationRequired</tt> flag is set to <tt>true</tt>. Subclasses
- * wishing to authorize the authenticated user credentials may override
- * this method to perform that authorization. On the other hand, the
- * <tt>authorize</tt> method of <tt>QueryServlet</tt> does nothing, so
- * subclasses that wish to authenticate the request but not authorize
- * it may simply not override this method.
- * <p>
- * This method is guaranteed to be called after the arguments and request
- * properties have been made available.
+ * Handles an HTTP GET request. The default implementation throws an HTTP
+ * 405 query exception.
*
- * @throws ServletException
- * If a servlet exception is thrown.
+ * @param path
*
- * @throws LoginException
- * If the request is not authorized.
+ * @throws QueryException
*/
- protected void authorize() throws ServletException, LoginException {
- // No-op
+ public void doDelete(String path) throws QueryException {
+ throw new QueryException(Query.Status.METHOD_NOT_ALLOWED);
}
@Override
@@ -401,100 +215,54 @@
protected void service(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
try {
- parameters.set(new QueryDictionary());
- requestHeaders.set(new QueryDictionary());
- responseHeaders.set(new QueryDictionary());
-
- boolean proceed = true;
-
- if (authenticationRequired) {
- String authorization = request.getHeader("Authorization");
-
- if (authorization == null) {
- proceed = false;
- doUnauthorized(request, response);
- } else {
- String encodedCredentials = authorization.substring
- (BASIC_AUTHENTICATION_TAG.length() + 1);
- String decodedCredentials = new String(Base64.decode(encodedCredentials));
- String[] credentialsPair = decodedCredentials.split(":");
-
- String username = credentialsPair.length > 0 ? credentialsPair[0] : "";
- String password = credentialsPair.length > 1 ? credentialsPair[1] : "";
-
- credentials.set(new Credentials(username, password));
- }
+ try {
+ URL url = new URL(request.getRequestURL().toString());
+ hostname.set(url.getHost());
+ port.set(request.getLocalPort());
+ servletPath.set(request.getServletPath());
+ secure.set(url.getProtocol().equalsIgnoreCase(HTTPS_PROTOCOL));
+ } catch (MalformedURLException exception) {
+ throw new ServletException(exception);
}
- if (proceed) {
- // Extract our location context
- try {
- URL url = new URL(request.getRequestURL().toString());
- String requestURI = request.getRequestURI();
- String requestContext = request.getContextPath();
-
- hostname.set(url.getHost());
- contextPath.set(requestContext);
- queryPath.set(requestURI);
- port.set(request.getLocalPort());
- secure.set(url.getProtocol().equalsIgnoreCase(HTTPS_PROTOCOL));
- method.set(Method.valueOf(request.getMethod().toUpperCase()));
-
- if (requestURI.startsWith(requestContext)) {
- queryPath.set(requestURI.substring(requestContext.length()));
- }
- } catch (MalformedURLException exception) {
- throw new ServletException(exception);
- }
+ parameters.set(new QueryDictionary(true));
+ requestHeaders.set(new QueryDictionary(false));
+ responseHeaders.set(new QueryDictionary(false));
+
+ // Copy the query string into the arguments dictionary
+ String queryString = request.getQueryString();
+ if (queryString != null) {
+ QueryDictionary parametersDictionary = parameters.get();
+ String[] pairs = queryString.split("&");
- // Copy the query string into our arguments dictionary
- String queryString = request.getQueryString();
- if (queryString != null) {
- QueryDictionary parametersDictionary = parameters.get();
- String[] pairs = queryString.split("&");
+ for (int i = 0, n = pairs.length; i < n; i++) {
+ String[] pair = pairs[i].split("=");
- for (int i = 0, n = pairs.length; i < n; i++) {
- String[] pair = pairs[i].split("=");
+ String key = URLDecoder.decode(pair[0], URL_ENCODING);
+ String value = URLDecoder.decode((pair.length > 1) ? pair[1] : "", URL_ENCODING);
- String key = URLDecoder.decode(pair[0], URL_ENCODING);
- String value = URLDecoder.decode((pair.length > 1) ? pair[1] : "", URL_ENCODING);
-
- parametersDictionary.add(key, value);
- }
+ parametersDictionary.add(key, value);
}
+ }
- // Copy the request headers into our request properties dictionary
- QueryDictionary requestHeaderDictionary = requestHeaders.get();
- Enumeration<String> headerNames = request.getHeaderNames();
- while (headerNames.hasMoreElements()) {
- String headerName = headerNames.nextElement();
- String headerValue = request.getHeader(headerName);
-
- requestHeaderDictionary.add(headerName, headerValue);
- }
+ // Copy the request headers into the request properties dictionary
+ QueryDictionary requestHeaderDictionary = requestHeaders.get();
+ Enumeration<String> headerNames = request.getHeaderNames();
+ while (headerNames.hasMoreElements()) {
+ String headerName = headerNames.nextElement();
+ String headerValue = request.getHeader(headerName);
- if (authenticationRequired) {
- try {
- authorize();
- } catch (LoginException exception) {
- proceed = false;
- doForbidden(request, response);
- }
- }
+ requestHeaderDictionary.add(headerName, headerValue);
}
- if (proceed) {
- super.service(request, response);
- }
+ // Call the base method to process the request
+ super.service(request, response);
} finally {
- // Clean up our thread local variables
- credentials.remove();
+ // Clean up thread local variables
hostname.remove();
- contextPath.remove();
- queryPath.remove();
port.remove();
+ servletPath.remove();
secure.remove();
- method.remove();
parameters.remove();
requestHeaders.remove();
responseHeaders.remove();
@@ -502,14 +270,19 @@
}
@Override
- @SuppressWarnings("unchecked")
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
- Serializer<Object> serializer = (Serializer<Object>)newSerializer();
+ Serializer<Object> serializer = createSerializer(request.getHeader(CONTENT_TYPE_HEADER));
+ Object result = null;
try {
- Object result = doGet();
+ result = doGet(request.getPathInfo());
+ } catch (QueryException exception) {
+ response.setStatus(exception.getStatus());
+ response.flushBuffer();
+ }
+ if (!response.isCommitted()) {
response.setStatus(200);
setResponseHeaders(response);
response.setContentType(serializer.getMIMEType(result));
@@ -517,20 +290,22 @@
OutputStream responseOutputStream = response.getOutputStream();
if (determineContentLength) {
- File tempFile = File.createTempFile("pivot", null);
+ File tempFile = File.createTempFile(getClass().getName(), null);
- // Serialize our result to an intermediary file
+ // Serialize the result to an intermediary file
FileOutputStream fileOutputStream = new FileOutputStream(tempFile);
try {
serializer.writeObject(result, fileOutputStream);
+ } catch (SerializationException exception) {
+ throw new ServletException(exception);
} finally {
fileOutputStream.close();
}
- // Our content length is the length of the file in bytes
- response.setHeader("Content-Length", String.valueOf(tempFile.length()));
+ // Set the content length header
+ response.setHeader(CONTENT_LENGTH_HEADER, String.valueOf(tempFile.length()));
- // Now write the contents of the file out to our response
+ // Write the contents of the file out to the response
FileInputStream fileInputStream = new FileInputStream(tempFile);
try {
byte[] buffer = new byte[1024];
@@ -545,61 +320,87 @@
fileInputStream.close();
}
} else {
- serializer.writeObject(result, responseOutputStream);
+ try {
+ serializer.writeObject(result, responseOutputStream);
+ } catch (SerializationException exception) {
+ throw new ServletException(exception);
+ }
}
- } catch (UnsupportedOperationException exception) {
- doMethodNotAllowed(response);
- } catch (ClientException exception) {
- doBadRequest(response);
- } catch (SerializationException exception) {
- throw new ServletException(exception);
+
+ response.flushBuffer();
}
}
@Override
protected final void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
- Serializer<?> serializer = newSerializer();
+ Serializer<Object> serializer = createSerializer(request.getHeader(CONTENT_TYPE_HEADER));
+ String action = request.getHeader(ACTION_HEADER);
- try {
- Object value = serializer.readObject(request.getInputStream());
+ if (action == null) {
+ Object value = null;
+ try {
+ value = serializer.readObject(request.getInputStream());
+ } catch (SerializationException exception) {
+ throw new ServletException(exception);
+ }
- URL url = doPost(value);
+ URL location = null;
+ try {
+ location = doPost(request.getPathInfo(), value);
+ } catch (QueryException exception) {
+ response.setStatus(exception.getStatus());
+ response.flushBuffer();
+ }
+
+ if (!response.isCommitted()) {
+ response.setStatus(201);
+ setResponseHeaders(response);
+ response.setHeader(LOCATION_HEADER, location.toString());
+ response.setContentLength(0);
+ }
+ } else {
+ try {
+ doPostAction(request.getPathInfo(), action);
+ } catch (QueryException exception) {
+ response.setStatus(exception.getStatus());
+ response.flushBuffer();
+ }
+
+ if (!response.isCommitted()) {
+ response.setStatus(204);
+ setResponseHeaders(response);
+ response.setContentLength(0);
+ }
- response.setStatus(201);
- setResponseHeaders(response);
- response.setHeader("Location", url.toString());
- response.setContentLength(0);
response.flushBuffer();
- } catch (UnsupportedOperationException exception) {
- doMethodNotAllowed(response);
- } catch (ClientException exception) {
- doBadRequest(response);
- } catch (SerializationException exception) {
- throw new ServletException(exception);
}
}
@Override
protected final void doPut(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
- Serializer<?> serializer = newSerializer();
+ Serializer<Object> serializer = createSerializer(request.getHeader(CONTENT_TYPE_HEADER));
+ Object value = null;
try {
- Object value = serializer.readObject(request.getInputStream());
+ value = serializer.readObject(request.getInputStream());
+ } catch (SerializationException exception) {
+ throw new ServletException(exception);
+ }
- doPut(value);
+ try {
+ doPut(request.getPathInfo(), value);
+ } catch (QueryException exception) {
+ response.setStatus(exception.getStatus());
+ response.flushBuffer();
+ }
+ if (!response.isCommitted()) {
response.setStatus(204);
setResponseHeaders(response);
response.setContentLength(0);
response.flushBuffer();
- } catch (UnsupportedOperationException exception) {
- doMethodNotAllowed(response);
- } catch (ClientException exception) {
- doBadRequest(response);
- } catch (SerializationException exception) {
- throw new ServletException(exception);
}
}
@@ -607,63 +408,66 @@
protected final void doDelete(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
try {
- doDelete();
+ doDelete(request.getPathInfo());
+ } catch (QueryException exception) {
+ response.setStatus(exception.getStatus());
+ response.flushBuffer();
+ }
+ if (!response.isCommitted()) {
response.setStatus(204);
setResponseHeaders(response);
response.setContentLength(0);
response.flushBuffer();
- } catch (UnsupportedOperationException exception) {
- doMethodNotAllowed(response);
- } catch (ClientException exception) {
- doBadRequest(response);
}
}
@Override
protected final void doHead(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
- doMethodNotAllowed(response);
+ response.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
+ response.flushBuffer();
}
@Override
protected final void doOptions(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
- doMethodNotAllowed(response);
+ response.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
+ response.flushBuffer();
}
@Override
protected final void doTrace(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
- doMethodNotAllowed(response);
- }
-
- private void doUnauthorized(HttpServletRequest request, HttpServletResponse response)
- throws IOException {
- response.setHeader("WWW-Authenticate", "BASIC realm=\""
- + request.getServletPath() +"\"");
- response.setStatus(401);
- response.setContentLength(0);
+ response.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
response.flushBuffer();
}
- private void doForbidden(HttpServletRequest request, HttpServletResponse response)
- throws IOException {
- response.setStatus(403);
- response.setContentLength(0);
- response.flushBuffer();
- }
+ @SuppressWarnings("unchecked")
+ private Serializer<Object> createSerializer(String mimeType)
+ throws ServletException {
+ if (mimeType == null) {
+ mimeType = JSONSerializer.MIME_TYPE;
+ } else {
+ mimeType = mimeType.substring(0, mimeType.indexOf(';'));
+ mimeType = mimeType.trim();
+ }
- private void doMethodNotAllowed(HttpServletResponse response) throws IOException {
- response.setStatus(405);
- response.setContentLength(0);
- response.flushBuffer();
- }
+ Class<? extends Serializer<?>> serializerType = serializerTypes.get(mimeType);
+ if (serializerType == null) {
+ throw new ServletException("A serializer for " + mimeType + " not found.");
+ }
- private void doBadRequest(HttpServletResponse response) throws IOException {
- response.setStatus(400);
- response.setContentLength(0);
- response.flushBuffer();
+ Serializer<Object> serializer = null;
+ try {
+ serializer = (Serializer<Object>)serializerType.newInstance();
+ } catch (InstantiationException exception) {
+ throw new ServletException(exception);
+ } catch (IllegalAccessException exception) {
+ throw new ServletException(exception);
+ }
+
+ return serializer;
}
private void setResponseHeaders(HttpServletResponse response) {
Modified: pivot/trunk/web/src/org/apache/pivot/web/Query.java
URL: http://svn.apache.org/viewvc/pivot/trunk/web/src/org/apache/pivot/web/Query.java?rev=904637&r1=904636&r2=904637&view=diff
==============================================================================
--- pivot/trunk/web/src/org/apache/pivot/web/Query.java (original)
+++ pivot/trunk/web/src/org/apache/pivot/web/Query.java Fri Jan 29 21:44:52 2010
@@ -139,9 +139,9 @@
private HostnameVerifier hostnameVerifier = null;
private Proxy proxy = null;
- private QueryDictionary parameters = new QueryDictionary();
- private QueryDictionary requestHeaders = new QueryDictionary();
- private QueryDictionary responseHeaders = new QueryDictionary();
+ private QueryDictionary parameters = new QueryDictionary(true);
+ private QueryDictionary requestHeaders = new QueryDictionary(false);
+ private QueryDictionary responseHeaders = new QueryDictionary(false);
private int status = 0;
private volatile long bytesExpected = -1;
Modified: pivot/trunk/web/src/org/apache/pivot/web/QueryDictionary.java
URL: http://svn.apache.org/viewvc/pivot/trunk/web/src/org/apache/pivot/web/QueryDictionary.java?rev=904637&r1=904636&r2=904637&view=diff
==============================================================================
--- pivot/trunk/web/src/org/apache/pivot/web/QueryDictionary.java (original)
+++ pivot/trunk/web/src/org/apache/pivot/web/QueryDictionary.java Fri Jan 29 21:44:52 2010
@@ -28,27 +28,46 @@
* multiple values to be set against a given key.
*/
public final class QueryDictionary implements Dictionary<String, String>, Iterable<String> {
- private HashMap<String, ArrayList<String>> map = new HashMap<String, ArrayList<String>>();
+ private boolean caseSensitiveKeys;
+ private HashMap<String, ArrayList<String>> map = new HashMap<String, ArrayList<String>>();
+
+ public QueryDictionary(boolean caseSensitiveKeys) {
+ this.caseSensitiveKeys = caseSensitiveKeys;
+ }
@Override
public String get(String key) {
+ if (caseSensitiveKeys) {
+ key = key.toLowerCase();
+ }
+
ArrayList<String> list = map.get(key);
if (list != null && list.getLength() > 0) {
return list.get(0);
}
+
return null;
}
public String get(String key, int index) {
+ if (caseSensitiveKeys) {
+ key = key.toLowerCase();
+ }
+
ArrayList<String> list = map.get(key);
if (list == null || list.getLength() <= index) {
throw new IndexOutOfBoundsException();
}
+
return list.get(index);
}
@Override
public String put(String key, String value) {
+ if (caseSensitiveKeys) {
+ key = key.toLowerCase();
+ }
+
ArrayList<String> list = new ArrayList<String>();
list.add(value);
@@ -61,6 +80,10 @@
}
public int add(String key, String value) {
+ if (caseSensitiveKeys) {
+ key = key.toLowerCase();
+ }
+
ArrayList<String> list = map.get(key);
if (list == null) {
put(key, value);
@@ -72,6 +95,10 @@
}
public void insert(String key, String value, int index) {
+ if (caseSensitiveKeys) {
+ key = key.toLowerCase();
+ }
+
ArrayList<String> list = map.get(key);
// e.g if index = 0 and length = 0, throw an exception
@@ -84,6 +111,10 @@
@Override
public String remove(String key) {
+ if (caseSensitiveKeys) {
+ key = key.toLowerCase();
+ }
+
ArrayList<String> list = map.remove(key);
if (list != null && list.getLength() > 0) {
return list.get(0);
@@ -93,10 +124,15 @@
}
public String remove(String key, int index) {
+ if (caseSensitiveKeys) {
+ key = key.toLowerCase();
+ }
+
ArrayList<String> list = map.get(key);
if (list == null || list.getLength() <= index) {
throw new IndexOutOfBoundsException();
}
+
return list.get(index);
}
@@ -106,11 +142,19 @@
@Override
public boolean containsKey(String key) {
+ if (caseSensitiveKeys) {
+ key = key.toLowerCase();
+ }
+
return map.containsKey(key);
}
public int getLength(String key) {
+ if (caseSensitiveKeys) {
+ key = key.toLowerCase();
+ }
+
ArrayList<String> list = map.get(key);
if (list == null) {
return 0;
Modified: pivot/trunk/web/test/org/apache/pivot/web/test/QueryDictionaryTest.java
URL: http://svn.apache.org/viewvc/pivot/trunk/web/test/org/apache/pivot/web/test/QueryDictionaryTest.java?rev=904637&r1=904636&r2=904637&view=diff
==============================================================================
--- pivot/trunk/web/test/org/apache/pivot/web/test/QueryDictionaryTest.java (original)
+++ pivot/trunk/web/test/org/apache/pivot/web/test/QueryDictionaryTest.java Fri Jan 29 21:44:52 2010
@@ -31,7 +31,7 @@
public class QueryDictionaryTest {
@Test(expected=IndexOutOfBoundsException.class)
public void testQueryDictionary() {
- QueryDictionary dict = new QueryDictionary();
+ QueryDictionary dict = new QueryDictionary(true);
assertNull(dict.get("key"));