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