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.codebehind;
22
23 import java.net.MalformedURLException;
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.HashMap;
27 import java.util.LinkedHashMap;
28 import java.util.List;
29 import java.util.Map;
30
31 import javax.servlet.ServletContext;
32
33 import org.apache.commons.logging.Log;
34 import org.apache.commons.logging.LogFactory;
35
36 import com.opensymphony.xwork2.Action;
37 import com.opensymphony.xwork2.ActionContext;
38 import com.opensymphony.xwork2.ActionSupport;
39 import com.opensymphony.xwork2.ObjectFactory;
40 import com.opensymphony.xwork2.Result;
41 import com.opensymphony.xwork2.UnknownHandler;
42 import com.opensymphony.xwork2.XWorkException;
43 import com.opensymphony.xwork2.config.Configuration;
44 import com.opensymphony.xwork2.config.ConfigurationException;
45 import com.opensymphony.xwork2.config.entities.ActionConfig;
46 import com.opensymphony.xwork2.config.entities.PackageConfig;
47 import com.opensymphony.xwork2.config.entities.ResultConfig;
48 import com.opensymphony.xwork2.config.entities.ResultTypeConfig;
49 import com.opensymphony.xwork2.config.providers.InterceptorBuilder;
50 import com.opensymphony.xwork2.inject.Inject;
51
52 /***
53 * Uses code-behind conventions to solve the two unknown problems.
54 */
55 public class CodebehindUnknownHandler implements UnknownHandler {
56
57 protected String defaultPackageName;
58 protected ServletContext servletContext;
59 protected Map<String,ResultTypeConfig> resultsByExtension;
60 protected String templatePathPrefix;
61 protected Configuration configuration;
62 protected ObjectFactory objectFactory;
63
64 protected static final Log LOG = LogFactory.getLog(CodebehindUnknownHandler.class);
65
66 @Inject
67 public CodebehindUnknownHandler(@Inject("struts.codebehind.defaultPackage") String defaultPackage,
68 @Inject Configuration configuration) {
69
70 this.configuration = configuration;
71 this.defaultPackageName = defaultPackage;
72 resultsByExtension = new LinkedHashMap<String,ResultTypeConfig>();
73 PackageConfig parentPackage = configuration.getPackageConfig(defaultPackageName);
74 if (parentPackage == null) {
75 throw new ConfigurationException("Unknown parent package: "+parentPackage);
76 }
77 Map<String,ResultTypeConfig> results = parentPackage.getAllResultTypeConfigs();
78
79 resultsByExtension.put("jsp", results.get("dispatcher"));
80 resultsByExtension.put("vm", results.get("velocity"));
81 resultsByExtension.put("ftl", results.get("freemarker"));
82
83 }
84
85 @Inject("struts.codebehind.pathPrefix")
86 public void setPathPrefix(String prefix) {
87 this.templatePathPrefix=prefix;
88 }
89
90 @Inject
91 public void setServletContext(ServletContext servletContext) {
92 this.servletContext = servletContext;
93 }
94
95 @Inject
96 public void setObjectFactory(ObjectFactory objectFactory) {
97 this.objectFactory = objectFactory;
98 }
99
100 public ActionConfig handleUnknownAction(String namespace, String actionName)
101 throws XWorkException {
102 String pathPrefix = determinePath(templatePathPrefix, namespace);
103 ActionConfig actionConfig = null;
104 for (String ext : resultsByExtension.keySet()) {
105 if (LOG.isDebugEnabled()) {
106 LOG.debug("Trying to locate unknown action template with extension ."+ext+" in directory "+pathPrefix);
107 }
108 String path = string(pathPrefix, actionName, "." , ext);
109 try {
110 if (servletContext.getResource(path) != null) {
111 actionConfig = buildActionConfig(path, namespace, actionName, resultsByExtension.get(ext));
112 break;
113 }
114 } catch (MalformedURLException e) {
115 LOG.warn("Unable to parse template path: "+path+", skipping...");
116 }
117 }
118 return actionConfig;
119 }
120
121 protected ActionConfig buildActionConfig(String path, String namespace, String actionName, ResultTypeConfig resultTypeConfig) {
122 Map<String,ResultConfig> results = new HashMap<String,ResultConfig>();
123 HashMap params = new HashMap();
124 if (resultTypeConfig.getParams() != null) {
125 params.putAll(resultTypeConfig.getParams());
126 }
127 params.put(resultTypeConfig.getDefaultResultParam(), path);
128
129 PackageConfig pkg = configuration.getPackageConfig(defaultPackageName);
130 List interceptors = InterceptorBuilder.constructInterceptorReference(pkg, pkg.getFullDefaultInterceptorRef(),
131 Collections.EMPTY_MAP, null, objectFactory);
132 ResultConfig config = new ResultConfig(Action.SUCCESS, resultTypeConfig.getClazz(), params);
133 results.put(Action.SUCCESS, config);
134 return new ActionConfig("execute", ActionSupport.class.getName(), defaultPackageName, new HashMap(), results, interceptors);
135 }
136
137 public Result handleUnknownResult(ActionContext actionContext, String actionName,
138 ActionConfig actionConfig, String resultCode) throws XWorkException {
139
140 Result result = null;
141 PackageConfig pkg = configuration.getPackageConfig(actionConfig.getPackageName());
142 String ns = pkg.getNamespace();
143 String pathPrefix = determinePath(templatePathPrefix, ns);
144
145 for (String ext : resultsByExtension.keySet()) {
146 if (LOG.isDebugEnabled()) {
147 LOG.debug("Trying to locate result with extension ."+ext+" in directory "+pathPrefix);
148 }
149 String path = string(pathPrefix, actionName, "-", resultCode, "." , ext);
150 try {
151 if (servletContext.getResource(path) != null) {
152 result = buildResult(path, resultCode, resultsByExtension.get(ext), actionContext);
153 break;
154 }
155 } catch (MalformedURLException e) {
156 LOG.warn("Unable to parse template path: "+path+", skipping...");
157 }
158
159 path = string(pathPrefix, actionName, "." , ext);
160 try {
161 if (servletContext.getResource(path) != null) {
162 result = buildResult(path, resultCode, resultsByExtension.get(ext), actionContext);
163 break;
164 }
165 } catch (MalformedURLException e) {
166 LOG.warn("Unable to parse template path: "+path+", skipping...");
167 }
168 }
169
170 return result;
171 }
172
173 protected Result buildResult(String path, String resultCode, ResultTypeConfig config, ActionContext invocationContext) {
174 String resultClass = config.getClazz();
175
176 Map<String,String> params = new LinkedHashMap<String,String>();
177 if (config.getParams() != null) {
178 params.putAll(config.getParams());
179 }
180 params.put(config.getDefaultResultParam(), path);
181
182 ResultConfig resultConfig = new ResultConfig(resultCode, resultClass, params);
183 try {
184 return objectFactory.buildResult(resultConfig, invocationContext.getContextMap());
185 } catch (Exception e) {
186 throw new XWorkException("Unable to build codebehind result", e, resultConfig);
187 }
188 }
189
190 protected String string(String... parts) {
191 StringBuilder sb = new StringBuilder();
192 for (String part : parts) {
193 sb.append(part);
194 }
195 return sb.toString();
196 }
197
198 protected String determinePath(String prefix, String ns) {
199 if (ns == null || "/".equals(ns)) {
200 ns = "";
201 }
202 if (ns.length() > 0) {
203 if (ns.charAt(0) == '/') {
204 ns = ns.substring(1);
205 }
206 if (ns.charAt(ns.length() - 1) != '/') {
207 ns += "/";
208 }
209 }
210 return prefix + ns;
211 }
212
213 }