diff --git a/spring-webflow/src/main/java/org/springframework/webflow/context/servlet/DefaultFlowUrlHandler.java b/spring-webflow/src/main/java/org/springframework/webflow/context/servlet/DefaultFlowUrlHandler.java index 5a2e0ea0..40a1c574 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/context/servlet/DefaultFlowUrlHandler.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/context/servlet/DefaultFlowUrlHandler.java @@ -58,6 +58,7 @@ import org.springframework.webflow.core.collection.AttributeMap; * execution "e1s1" of the "hotels/booking" flow. * * @author Keith Donald + * @author Jeremy Grelle */ public class DefaultFlowUrlHandler implements FlowUrlHandler { @@ -109,6 +110,23 @@ public class DefaultFlowUrlHandler implements FlowUrlHandler { return url.toString(); } + /** + * The flow definition URL for the given flow id will be built by appending the flow id to the base app context and + * servlet paths. + * + *

+ * Example - given a request originating at: + * + *

+	 * http://someHost/someApp/someServlet/nestedPath/foo
+	 * 
+ * + * and a request for the flow id "nestedPath/bar", the new flow definition URL would be: + * + *
+	 * http://someHost/someApp/someServlet/nestedPath/bar
+	 * 
+ */ public String createFlowDefinitionUrl(String flowId, AttributeMap input, HttpServletRequest request) { StringBuffer url = new StringBuffer(); if (request.getPathInfo() != null) { @@ -138,9 +156,7 @@ public class DefaultFlowUrlHandler implements FlowUrlHandler { return url.toString(); } - // internal helpers - - private String getEncodingScheme(HttpServletRequest request) { + protected String getEncodingScheme(HttpServletRequest request) { if (encodingScheme != null) { return encodingScheme; } else { @@ -152,7 +168,7 @@ public class DefaultFlowUrlHandler implements FlowUrlHandler { } } - private void appendQueryParameters(StringBuffer url, Map parameters, String encodingScheme) { + protected void appendQueryParameters(StringBuffer url, Map parameters, String encodingScheme) { Iterator entries = parameters.entrySet().iterator(); while (entries.hasNext()) { Map.Entry entry = (Map.Entry) entries.next(); @@ -163,6 +179,8 @@ public class DefaultFlowUrlHandler implements FlowUrlHandler { } } + // internal helpers + private void appendQueryParameter(StringBuffer url, Object key, Object value, String encodingScheme) { String encodedKey = encode(key, encodingScheme); String encodedValue = encode(value, encodingScheme); diff --git a/spring-webflow/src/main/java/org/springframework/webflow/context/servlet/FilenameFlowUrlHandler.java b/spring-webflow/src/main/java/org/springframework/webflow/context/servlet/FilenameFlowUrlHandler.java index f7f7ada6..d00c9a22 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/context/servlet/FilenameFlowUrlHandler.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/context/servlet/FilenameFlowUrlHandler.java @@ -17,14 +17,16 @@ package org.springframework.webflow.context.servlet; import javax.servlet.http.HttpServletRequest; +import org.springframework.util.StringUtils; import org.springframework.web.util.UrlPathHelper; import org.springframework.web.util.WebUtils; +import org.springframework.webflow.core.collection.AttributeMap; import org.springframework.webflow.mvc.servlet.FlowController; /** * A file name based {@link FlowUrlHandler} implementation that is an alternative to the standard * {@link DefaultFlowUrlHandler}. Treats the filename of a request without the URL suffix and/or prefix as the flow id. - * Used by the {@link FlowController} implementation as a default implementation to preserve compability with existing + * Used by the {@link FlowController} implementation as a default implementation to preserve compatibility with existing * Web Flow 2 applications. * *

@@ -54,6 +56,8 @@ import org.springframework.webflow.mvc.servlet.FlowController; * well to avoid these clashes. * * @author Agim Emruli + * @author Jeremy Grelle + * @author Nazaret Kazarian */ public class FilenameFlowUrlHandler extends DefaultFlowUrlHandler { @@ -66,4 +70,63 @@ public class FilenameFlowUrlHandler extends DefaultFlowUrlHandler { public String getFlowId(HttpServletRequest request) { return WebUtils.extractFilenameFromUrlPath(urlPathHelper.getLookupPathForRequest(request)); } + + /** + * The flow definition URL for the given flowId will be inferred from the URL of the current request, re-using the + * same path and file extension. + * + *

+ * Example - given a request originating at: + * + *

+	 * http://someHost/someApp/someServlet/nestedPath/foo.html
+	 * 
+ * + * and a request for the flow id "bar", the new flow definition URL would be: + * + *
+	 * http://someHost/someApp/someServlet/nestedPath/bar.html
+	 * 
+ */ + public String createFlowDefinitionUrl(String flowId, AttributeMap input, HttpServletRequest request) { + StringBuffer url = new StringBuffer(); + String pathInfo = request.getPathInfo(); + if (pathInfo != null) { + url.append(request.getContextPath()); + url.append(request.getServletPath()); + // include the pathInfo part up until the filename + url.append(pathInfo.substring(0, pathInfo.lastIndexOf("/") + 1)); + url.append(flowId); + int dotIndex = pathInfo.lastIndexOf('.'); + if (dotIndex != -1) { + url.append(pathInfo.substring(dotIndex)); + } + } else { + String servletPath = request.getServletPath(); + if (StringUtils.hasText(servletPath)) { + url.append(request.getContextPath()); + // include the servletPath part up to the filename + int slashIndex = servletPath.lastIndexOf("/"); + if (slashIndex != -1) { + url.append(servletPath.substring(0, slashIndex)); + } + url.append('/'); + url.append(flowId); + int dotIndex = servletPath.lastIndexOf('.'); + if (dotIndex != -1) { + url.append(servletPath.substring(dotIndex)); + } + } else { + // Leaving this for now, as DefaultFlowUrlHandler does the same thing, + // but this should probably be an error case in the future. + url.append('/'); + url.append(flowId); + } + } + if (input != null && !input.isEmpty()) { + url.append('?'); + appendQueryParameters(url, input.asMap(), getEncodingScheme(request)); + } + return url.toString(); + } } \ No newline at end of file diff --git a/spring-webflow/src/test/java/org/springframework/webflow/context/servlet/FilenameFlowUrlHandlerTests.java b/spring-webflow/src/test/java/org/springframework/webflow/context/servlet/FilenameFlowUrlHandlerTests.java index 706e29f0..21a8ea29 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/context/servlet/FilenameFlowUrlHandlerTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/context/servlet/FilenameFlowUrlHandlerTests.java @@ -45,4 +45,39 @@ public class FilenameFlowUrlHandlerTests extends TestCase { request.setRequestURI("/springtravel"); assertEquals("", urlHandler.getFlowId(request)); } + + public void testCreateFlowDefinitionUrlWithPathInfo() { + request.setContextPath("/springtravel"); + request.setServletPath("/app"); + request.setPathInfo("/foo"); + request.setRequestURI("/springtravel/app/foo"); + String flowDefUrl = urlHandler.createFlowDefinitionUrl("bar", null, request); + assertEquals("/springtravel/app/bar", flowDefUrl); + } + + public void testCreateFlowDefinitionUrlWithPathInfoNestedPath() { + request.setContextPath("/springtravel"); + request.setServletPath("/app"); + request.setPathInfo("/nestedPath/foo"); + request.setRequestURI("/springtravel/app/nestedPath/foo"); + String flowDefUrl = urlHandler.createFlowDefinitionUrl("bar", null, request); + assertEquals("/springtravel/app/nestedPath/bar", flowDefUrl); + } + + public void testCreateFlowDefinitionUrlWithPathInfoNestedPathAndFileExtension() { + request.setContextPath("/springtravel"); + request.setServletPath("/app"); + request.setPathInfo("/nestedPath/foo.flow"); + request.setRequestURI("/springtravel/app/nestedPath/foo.flow"); + String flowDefUrl = urlHandler.createFlowDefinitionUrl("bar", null, request); + assertEquals("/springtravel/app/nestedPath/bar.flow", flowDefUrl); + } + + public void testCreateFlowDefinitionUrlWithServletPathAndFileExtension() { + request.setContextPath("/springtravel"); + request.setServletPath("/nestedPath/foo.flow"); + request.setRequestURI("/springtravel/nestedPath/foo.flow"); + String flowDefUrl = urlHandler.createFlowDefinitionUrl("bar", null, request); + assertEquals("/springtravel/nestedPath/bar.flow", flowDefUrl); + } } \ No newline at end of file