1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.struts2.dispatcher.mapper;
22
23 import java.net.URLDecoder;
24 import java.util.HashMap;
25 import java.util.Iterator;
26 import java.util.Map;
27 import java.util.StringTokenizer;
28
29 import javax.servlet.http.HttpServletRequest;
30
31 import org.apache.commons.logging.Log;
32 import org.apache.commons.logging.LogFactory;
33 import org.apache.struts2.RequestUtils;
34
35 import com.opensymphony.xwork2.config.ConfigurationManager;
36
37
38 /***
39 * <!-- START SNIPPET: description -->
40 *
41 * A custom action mapper using the following format:
42 * <p/>
43 * <p/>
44 * <ul><tt>http://HOST/ACTION_NAME/PARAM_NAME1/PARAM_VALUE1/PARAM_NAME2/PARAM_VALUE2</tt></ul>
45 * <p/>
46 * You can have as many parameters you'd like to use. Alternatively the URL can be shortened to the following:
47 * <p/>
48 * <ul><tt>http://HOST/ACTION_NAME/PARAM_VALUE1/PARAM_NAME2/PARAM_VALUE2</tt></ul>
49 * <p/>
50 * This is the same as:
51 * <p/>
52 * <ul><tt>http://HOST/ACTION_NAME/ACTION_NAME + "Id"/PARAM_VALUE1/PARAM_NAME2/PARAM_VALUE2</tt></ul>
53 * <p/>
54 * Suppose for example we would like to display some articles by id at using the following URL sheme:
55 * <p/>
56 * <ul><tt>http://HOST/article/Id</tt></ul>
57 * <p/>
58 * <p/>
59 * Your action just needs a setArticleId() method, and requests such as /article/1, /article/2, etc will all map
60 * to that URL pattern.
61 *
62 * <!-- END SNIPPET: description -->
63 *
64 */
65 public class RestfulActionMapper implements ActionMapper {
66 protected static final Log LOG = LogFactory.getLog(RestfulActionMapper.class);
67
68
69
70
71 public ActionMapping getMapping(HttpServletRequest request, ConfigurationManager configManager) {
72 String uri = RequestUtils.getServletPath(request);
73
74 int nextSlash = uri.indexOf('/', 1);
75 if (nextSlash == -1) {
76 return null;
77 }
78
79 String actionName = uri.substring(1, nextSlash);
80 HashMap<String,String> parameters = new HashMap<String,String>();
81 try {
82 StringTokenizer st = new StringTokenizer(uri.substring(nextSlash), "/");
83 boolean isNameTok = true;
84 String paramName = null;
85 String paramValue;
86
87
88 if ((st.countTokens() % 2) != 0) {
89 isNameTok = false;
90 paramName = actionName + "Id";
91 }
92
93 while (st.hasMoreTokens()) {
94 if (isNameTok) {
95 paramName = URLDecoder.decode(st.nextToken(), "UTF-8");
96 isNameTok = false;
97 } else {
98 paramValue = URLDecoder.decode(st.nextToken(), "UTF-8");
99
100 if ((paramName != null) && (paramName.length() > 0)) {
101 parameters.put(paramName, paramValue);
102 }
103
104 isNameTok = true;
105 }
106 }
107 } catch (Exception e) {
108 LOG.warn(e);
109 }
110
111 return new ActionMapping(actionName, "", "", parameters);
112 }
113
114
115
116
117 public String getUriFromActionMapping(ActionMapping mapping) {
118 String base = mapping.getNamespace() + mapping.getName();
119 for (Iterator iterator = mapping.getParams().entrySet().iterator(); iterator.hasNext();) {
120 Map.Entry entry = (Map.Entry) iterator.next();
121 String name = (String) entry.getKey();
122 if (name.equals(mapping.getName() + "Id")) {
123 base = base + "/" + entry.getValue();
124 break;
125 }
126 }
127
128 return base;
129 }
130 }