1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.struts.config;
22
23 import org.apache.commons.beanutils.BeanUtils;
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26 import org.apache.struts.action.ActionForward;
27 import org.apache.struts.util.WildcardHelper;
28
29 import java.io.Serializable;
30
31 import java.util.ArrayList;
32 import java.util.HashMap;
33 import java.util.Iterator;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.Properties;
37
38
39
40
41
42
43
44
45
46
47 public class ActionConfigMatcher implements Serializable {
48
49
50
51 private static final Log log = LogFactory.getLog(ActionConfigMatcher.class);
52
53
54
55
56 private static final WildcardHelper wildcard = new WildcardHelper();
57
58
59
60
61 private List compiledPaths;
62
63
64
65
66
67
68
69
70
71 public ActionConfigMatcher(ActionConfig[] configs) {
72 compiledPaths = new ArrayList();
73
74 int[] pattern;
75 String path;
76
77 for (int x = 0; x < configs.length; x++) {
78 path = configs[x].getPath();
79
80 if ((path != null) && (path.indexOf('*') > -1)) {
81 if ((path.length() > 0) && (path.charAt(0) == '/')) {
82 path = path.substring(1);
83 }
84
85 if (log.isDebugEnabled()) {
86 log.debug("Compiling action config path '" + path + "'");
87 }
88
89 pattern = wildcard.compilePattern(path);
90 compiledPaths.add(new Mapping(pattern, configs[x]));
91 }
92 }
93 }
94
95
96
97
98
99
100
101 public ActionConfig match(String path) {
102 ActionConfig config = null;
103
104 if (compiledPaths.size() > 0) {
105 if (log.isDebugEnabled()) {
106 log.debug("Attempting to match '" + path
107 + "' to a wildcard pattern");
108 }
109
110 if ((path.length() > 0) && (path.charAt(0) == '/')) {
111 path = path.substring(1);
112 }
113
114 Mapping m;
115 HashMap vars = new HashMap();
116
117 for (Iterator i = compiledPaths.iterator(); i.hasNext();) {
118 m = (Mapping) i.next();
119
120 if (wildcard.match(vars, path, m.getPattern())) {
121 if (log.isDebugEnabled()) {
122 log.debug("Path matches pattern '"
123 + m.getActionConfig().getPath() + "'");
124 }
125
126 config =
127 convertActionConfig(path,
128 (ActionConfig) m.getActionConfig(), vars);
129 }
130 }
131 }
132
133 return config;
134 }
135
136
137
138
139
140
141
142
143
144
145
146 protected ActionConfig convertActionConfig(String path, ActionConfig orig,
147 Map vars) {
148 ActionConfig config = null;
149
150 try {
151 config = (ActionConfig) BeanUtils.cloneBean(orig);
152 } catch (Exception ex) {
153 log.warn("Unable to clone action config, recommend not using "
154 + "wildcards", ex);
155
156 return null;
157 }
158
159 config.setName(convertParam(orig.getName(), vars));
160
161 if ((path.length() == 0) || (path.charAt(0) != '/')) {
162 path = "/" + path;
163 }
164
165 config.setPath(path);
166 config.setType(convertParam(orig.getType(), vars));
167 config.setRoles(convertParam(orig.getRoles(), vars));
168 config.setParameter(convertParam(orig.getParameter(), vars));
169 config.setAttribute(convertParam(orig.getAttribute(), vars));
170 config.setForward(convertParam(orig.getForward(), vars));
171 config.setInclude(convertParam(orig.getInclude(), vars));
172 config.setInput(convertParam(orig.getInput(), vars));
173 config.setCatalog(convertParam(orig.getCatalog(), vars));
174 config.setCommand(convertParam(orig.getCommand(), vars));
175 config.setMultipartClass(convertParam(orig.getMultipartClass(), vars));
176 config.setPrefix(convertParam(orig.getPrefix(), vars));
177 config.setSuffix(convertParam(orig.getSuffix(), vars));
178
179 ForwardConfig[] fConfigs = orig.findForwardConfigs();
180 ForwardConfig cfg;
181
182 for (int x = 0; x < fConfigs.length; x++) {
183 try {
184 cfg = (ActionForward) BeanUtils.cloneBean(fConfigs[x]);
185 } catch (Exception ex) {
186 log.warn("Unable to clone action config, recommend not using "
187 + "wildcards", ex);
188 return null;
189 }
190 cfg.setName(fConfigs[x].getName());
191 cfg.setPath(convertParam(fConfigs[x].getPath(), vars));
192 cfg.setRedirect(fConfigs[x].getRedirect());
193 cfg.setCommand(convertParam(fConfigs[x].getCommand(), vars));
194 cfg.setCatalog(convertParam(fConfigs[x].getCatalog(), vars));
195 cfg.setModule(convertParam(fConfigs[x].getModule(), vars));
196
197 replaceProperties(fConfigs[x].getProperties(), cfg.getProperties(),
198 vars);
199
200 config.removeForwardConfig(fConfigs[x]);
201 config.addForwardConfig(cfg);
202 }
203
204 replaceProperties(orig.getProperties(), config.getProperties(), vars);
205
206 ExceptionConfig[] exConfigs = orig.findExceptionConfigs();
207
208 for (int x = 0; x < exConfigs.length; x++) {
209 config.addExceptionConfig(exConfigs[x]);
210 }
211
212 config.freeze();
213
214 return config;
215 }
216
217
218
219
220
221
222
223
224
225 protected void replaceProperties(Properties orig, Properties props, Map vars) {
226 Map.Entry entry = null;
227
228 for (Iterator i = orig.entrySet().iterator(); i.hasNext();) {
229 entry = (Map.Entry) i.next();
230 props.setProperty((String) entry.getKey(),
231 convertParam((String) entry.getValue(), vars));
232 }
233 }
234
235
236
237
238
239
240
241
242
243 protected String convertParam(String val, Map vars) {
244 if (val == null) {
245 return null;
246 } else if (val.indexOf("{") == -1) {
247 return val;
248 }
249
250 Map.Entry entry;
251 StringBuffer key = new StringBuffer("{0}");
252 StringBuffer ret = new StringBuffer(val);
253 String keyTmp;
254 int x;
255
256 for (Iterator i = vars.entrySet().iterator(); i.hasNext();) {
257 entry = (Map.Entry) i.next();
258 key.setCharAt(1, ((String) entry.getKey()).charAt(0));
259 keyTmp = key.toString();
260
261
262 while ((x = ret.toString().indexOf(keyTmp)) > -1) {
263 ret.replace(x, x + 3, (String) entry.getValue());
264 }
265 }
266
267 return ret.toString();
268 }
269
270
271
272
273
274 private class Mapping implements Serializable {
275
276
277
278 private int[] pattern;
279
280
281
282
283 private ActionConfig config;
284
285
286
287
288
289
290
291 public Mapping(int[] pattern, ActionConfig config) {
292 this.pattern = pattern;
293 this.config = config;
294 }
295
296
297
298
299
300
301 public int[] getPattern() {
302 return this.pattern;
303 }
304
305
306
307
308
309
310 public ActionConfig getActionConfig() {
311 return this.config;
312 }
313 }
314 }