Author: jeromy Date: Mon Jun 30 00:54:36 2008 New Revision: 672721 URL: http://svn.apache.org/viewvc?rev=672721&view=rev Log: WW-2641 Separated the request and response ContentTypeHandlers. Added x-www-form-urlencoded handler
Added: struts/struts2/trunk/plugins/rest/src/main/java/org/apache/struts2/rest/handler/FormUrlEncodedHandler.java Modified: struts/struts2/trunk/plugins/rest/src/main/java/org/apache/struts2/rest/ContentTypeHandlerManager.java struts/struts2/trunk/plugins/rest/src/main/resources/struts-plugin.xml struts/struts2/trunk/plugins/rest/src/test/java/org/apache/struts2/rest/ContentTypeHandlerManagerTest.java Modified: struts/struts2/trunk/plugins/rest/src/main/java/org/apache/struts2/rest/ContentTypeHandlerManager.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/rest/src/main/java/org/apache/struts2/rest/ContentTypeHandlerManager.java?rev=672721&r1=672720&r2=672721&view=diff ============================================================================== --- struts/struts2/trunk/plugins/rest/src/main/java/org/apache/struts2/rest/ContentTypeHandlerManager.java (original) +++ struts/struts2/trunk/plugins/rest/src/main/java/org/apache/struts2/rest/ContentTypeHandlerManager.java Mon Jun 30 00:54:36 2008 @@ -44,7 +44,11 @@ */ public class ContentTypeHandlerManager { - Map<String,ContentTypeHandler> handlers = new HashMap<String,ContentTypeHandler>(); + /** ContentTypeHandlers keyed by the extension */ + Map<String,ContentTypeHandler> handlersByExtension = new HashMap<String,ContentTypeHandler>(); + /** ContentTypeHandlers keyed by the content-type */ + Map<String,ContentTypeHandler> handlersByContentType = new HashMap<String,ContentTypeHandler>(); + String defaultExtension; public static final String STRUTS_REST_HANDLER_OVERRIDE_PREFIX = "struts.rest.handlerOverride."; @@ -59,33 +63,60 @@ for (String name : names) { ContentTypeHandler handler = container.getInstance(ContentTypeHandler.class, name); - // Check for overriding handlers for the current extension - String overrideName = container.getInstance(String.class, STRUTS_REST_HANDLER_OVERRIDE_PREFIX +handler.getExtension()); - if (overrideName != null) { - if (!handlers.containsKey(handler.getExtension())) { - handler = container.getInstance(ContentTypeHandler.class, overrideName); - } else { - // overriding handler has already been registered - continue; + if (handler.getExtension() != null) { + // Check for overriding handlers for the current extension + String overrideName = container.getInstance(String.class, STRUTS_REST_HANDLER_OVERRIDE_PREFIX +handler.getExtension()); + if (overrideName != null) { + if (!handlersByExtension.containsKey(handler.getExtension())) { + handler = container.getInstance(ContentTypeHandler.class, overrideName); + } else { + // overriding handler has already been registered + continue; + } } + this.handlersByExtension.put(handler.getExtension(), handler); + } + + if (handler.getContentType() != null) { + this.handlersByContentType.put(handler.getContentType(), handler); } - this.handlers.put(handler.getExtension(), handler); } } /** - * Gets the handler for the request by looking at the extension + * Gets the handler for the request by looking at the request content type and extension * @param req The request * @return The appropriate handler */ public ContentTypeHandler getHandlerForRequest(HttpServletRequest req) { + ContentTypeHandler handler = null; + String contentType = req.getContentType(); + if (contentType != null) { + handler = handlersByContentType.get(contentType); + } + if (handler == null) { + String extension = findExtension(req.getRequestURI()); + if (extension == null) { + extension = defaultExtension; + } + handler = handlersByExtension.get(extension); + } + return handler; + } + + /** + * Gets the handler for the response by looking at the extension of the request + * @param req The request + * @return The appropriate handler + */ + public ContentTypeHandler getHandlerForResponse(HttpServletRequest req, HttpServletResponse res) { String extension = findExtension(req.getRequestURI()); if (extension == null) { extension = defaultExtension; } - return handlers.get(extension); + return handlersByExtension.get(extension); } - + /** * Handles the result using handlers to generate content type-specific content * @@ -127,7 +158,7 @@ target = null; } - ContentTypeHandler handler = getHandlerForRequest(req); + ContentTypeHandler handler = getHandlerForResponse(req, res); if (handler != null) { String extCode = resultCode+"-"+handler.getExtension(); if (actionConfig.getResults().get(extCode) != null) { Added: struts/struts2/trunk/plugins/rest/src/main/java/org/apache/struts2/rest/handler/FormUrlEncodedHandler.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/rest/src/main/java/org/apache/struts2/rest/handler/FormUrlEncodedHandler.java?rev=672721&view=auto ============================================================================== --- struts/struts2/trunk/plugins/rest/src/main/java/org/apache/struts2/rest/handler/FormUrlEncodedHandler.java (added) +++ struts/struts2/trunk/plugins/rest/src/main/java/org/apache/struts2/rest/handler/FormUrlEncodedHandler.java Mon Jun 30 00:54:36 2008 @@ -0,0 +1,60 @@ +/* + * $Id$ + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.struts2.rest.handler; + +import java.io.Writer; +import java.io.IOException; +import java.io.Reader; + +/** + * Handles the default content type for requests that originate from a browser's HTML form + * + * content-type: application/x-www-form-urlencoded + * + * This handler is intended for requests only, not for responses + * + * [EMAIL PROTECTED] http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4} + * + */ +public class FormUrlEncodedHandler implements ContentTypeHandler { + + public static final String CONTENT_TYPE = "application/x-www-form-urlencoded"; + + public String fromObject(Object obj, String resultCode, Writer out) throws IOException { + throw new IOException("Conversion from Object to '"+getContentType()+"' is not supported"); + } + + /** No transformation is required as the framework handles this data */ + public void toObject(Reader in, Object target) { + } + + /** + * The extension is not used by this handler + * @return + */ + public String getExtension() { + return null; + } + + public String getContentType() { + return CONTENT_TYPE; + } +} Modified: struts/struts2/trunk/plugins/rest/src/main/resources/struts-plugin.xml URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/rest/src/main/resources/struts-plugin.xml?rev=672721&r1=672720&r2=672721&view=diff ============================================================================== --- struts/struts2/trunk/plugins/rest/src/main/resources/struts-plugin.xml (original) +++ struts/struts2/trunk/plugins/rest/src/main/resources/struts-plugin.xml Mon Jun 30 00:54:36 2008 @@ -35,6 +35,7 @@ <bean type="org.apache.struts2.rest.handler.ContentTypeHandler" name="xml" class="org.apache.struts2.rest.handler.XStreamHandler" /> <bean type="org.apache.struts2.rest.handler.ContentTypeHandler" name="json" class="org.apache.struts2.rest.handler.JsonLibHandler" /> <bean type="org.apache.struts2.rest.handler.ContentTypeHandler" name="html" class="org.apache.struts2.rest.handler.HtmlHandler" /> + <bean type="org.apache.struts2.rest.handler.ContentTypeHandler" name="x-www-form-urlencoded" class="org.apache.struts2.rest.handler.FormUrlEncodedHandler" /> <constant name="struts.actionProxyFactory" value="rest" /> <constant name="struts.rest.defaultExtension" value="xhtml" /> Modified: struts/struts2/trunk/plugins/rest/src/test/java/org/apache/struts2/rest/ContentTypeHandlerManagerTest.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/rest/src/test/java/org/apache/struts2/rest/ContentTypeHandlerManagerTest.java?rev=672721&r1=672720&r2=672721&view=diff ============================================================================== --- struts/struts2/trunk/plugins/rest/src/test/java/org/apache/struts2/rest/ContentTypeHandlerManagerTest.java (original) +++ struts/struts2/trunk/plugins/rest/src/test/java/org/apache/struts2/rest/ContentTypeHandlerManagerTest.java Mon Jun 30 00:54:36 2008 @@ -29,6 +29,7 @@ import junit.framework.TestCase; import org.apache.struts2.ServletActionContext; import org.apache.struts2.rest.handler.ContentTypeHandler; +import org.apache.struts2.rest.handler.FormUrlEncodedHandler; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; @@ -78,7 +79,7 @@ public String getContentType() { return "foo"; } public String getExtension() { return "foo"; } }; - mgr.handlers.put("xml", handler); + mgr.handlersByExtension.put("xml", handler); mgr.defaultExtension = "xml"; mgr.handleResult(new ActionConfig.Builder("", "", "").build(), new DefaultHttpHeaders().withStatus(SC_OK), obj); @@ -89,7 +90,7 @@ Mock mockHandlerXml = new Mock(ContentTypeHandler.class); mockHandlerXml.matchAndReturn("getExtension", "xml"); - mgr.handlers.put("xml", (ContentTypeHandler) mockHandlerXml.proxy()); + mgr.handlersByExtension.put("xml", (ContentTypeHandler) mockHandlerXml.proxy()); mgr.handleResult(null, new DefaultHttpHeaders().withStatus(SC_NOT_MODIFIED), new Object()); assertEquals(0, mockResponse.getContentLength()); @@ -98,13 +99,16 @@ public void testHandlerOverride() { Mock mockHandlerXml = new Mock(ContentTypeHandler.class); mockHandlerXml.matchAndReturn("getExtension", "xml"); + mockHandlerXml.matchAndReturn("getContentType", "application/xml"); mockHandlerXml.matchAndReturn("toString", "xml"); Mock mockHandlerJson = new Mock(ContentTypeHandler.class); mockHandlerJson.matchAndReturn("getExtension", "json"); + mockHandlerJson.matchAndReturn("getContentType", "application/javascript"); mockHandlerJson.matchAndReturn("toString", "json"); Mock mockHandlerXmlOverride = new Mock(ContentTypeHandler.class); mockHandlerXmlOverride.matchAndReturn("getExtension", "xml"); mockHandlerXmlOverride.matchAndReturn("toString", "xmlOverride"); + mockHandlerXmlOverride.matchAndReturn("getContentType", "application/xml"); Mock mockContainer = new Mock(Container.class); mockContainer.matchAndReturn("getInstance", C.args(C.eq(ContentTypeHandler.class), C.eq("xmlOverride")), mockHandlerXmlOverride.proxy()); @@ -120,10 +124,34 @@ ContentTypeHandlerManager mgr = new ContentTypeHandlerManager(); mgr.setContainer((Container) mockContainer.proxy()); - Map<String,ContentTypeHandler> handlers = mgr.handlers; + Map<String,ContentTypeHandler> handlers = mgr.handlersByExtension; assertNotNull(handlers); assertEquals(2, handlers.size()); assertEquals(mockHandlerXmlOverride.proxy(), handlers.get("xml")); assertEquals(mockHandlerJson.proxy(), handlers.get("json")); } + + /** Assert that the request content-type and differ from the response content type */ + public void HandleRequestContentType() throws IOException { + + Mock mockHandlerForm = new Mock(ContentTypeHandler.class); + mockHandlerForm.matchAndReturn("getExtension", null); + mockHandlerForm.matchAndReturn("getContentType", "application/x-www-form-urlencoded"); + mockHandlerForm.matchAndReturn("toString", "x-www-form-urlencoded"); + + Mock mockHandlerJson = new Mock(ContentTypeHandler.class); + mockHandlerJson.matchAndReturn("getExtension", "json"); + mockHandlerJson.matchAndReturn("getContentType", "application/javascript"); + mockHandlerJson.matchAndReturn("toString", "json"); + + Mock mockContainer = new Mock(Container.class); + mockContainer.matchAndReturn("getInstance", C.args(C.eq(ContentTypeHandler.class), C.eq("x-www-form-urlencoded")), mockHandlerForm.proxy()); + mockContainer.expectAndReturn("getInstanceNames", C.args(C.eq(ContentTypeHandler.class)), new HashSet(Arrays.asList("x-www-form-urlencoded", "json"))); + + mockRequest.setContentType(FormUrlEncodedHandler.CONTENT_TYPE); + mockRequest.setContent("a=1&b=2".getBytes("UTF-8")); + ContentTypeHandler handler = mgr.getHandlerForRequest(mockRequest); + + assertEquals("x-www-form-urlencoded", toString()); + } }