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.codebehind;
23
24 import java.net.MalformedURLException;
25 import java.net.URL;
26 import java.util.Collections;
27 import java.util.HashMap;
28 import java.util.LinkedHashMap;
29 import java.util.List;
30 import java.util.Map;
31
32 import javax.servlet.ServletContext;
33
34 import org.apache.struts2.util.ClassLoaderUtils;
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.*;
46 import com.opensymphony.xwork2.config.providers.InterceptorBuilder;
47 import com.opensymphony.xwork2.inject.Inject;
48 import com.opensymphony.xwork2.util.logging.Logger;
49 import com.opensymphony.xwork2.util.logging.LoggerFactory;
50
51 /***
52 * Uses code-behind conventions to solve the two unknown problems.
53 */
54 public class CodebehindUnknownHandler implements UnknownHandler {
55
56 protected String defaultPackageName;
57 protected ServletContext servletContext;
58 protected Map<String,ResultTypeConfig> resultsByExtension;
59 protected String templatePathPrefix;
60 protected Configuration configuration;
61 protected ObjectFactory objectFactory;
62
63 protected static final Logger LOG = LoggerFactory.getLogger(CodebehindUnknownHandler.class);
64
65 @Inject
66 public CodebehindUnknownHandler(@Inject("struts.codebehind.defaultPackage") String defaultPackage,
67 @Inject Configuration configuration) {
68
69 this.configuration = configuration;
70 this.defaultPackageName = defaultPackage;
71 resultsByExtension = new LinkedHashMap<String,ResultTypeConfig>();
72 PackageConfig parentPackage = configuration.getPackageConfig(defaultPackageName);
73 if (parentPackage == null) {
74 throw new ConfigurationException("Unknown parent package: "+parentPackage);
75 }
76 Map<String,ResultTypeConfig> results = parentPackage.getAllResultTypeConfigs();
77
78 resultsByExtension.put("jsp", results.get("dispatcher"));
79 resultsByExtension.put("vm", results.get("velocity"));
80 resultsByExtension.put("ftl", results.get("freemarker"));
81
82 }
83
84 @Inject("struts.codebehind.pathPrefix")
85 public void setPathPrefix(String prefix) {
86 this.templatePathPrefix=prefix;
87 }
88
89 @Inject
90 public void setServletContext(ServletContext servletContext) {
91 this.servletContext = servletContext;
92 }
93
94 @Inject
95 public void setObjectFactory(ObjectFactory objectFactory) {
96 this.objectFactory = objectFactory;
97 }
98
99 public ActionConfig handleUnknownAction(String namespace, String actionName)
100 throws XWorkException {
101 String pathPrefix = determinePath(templatePathPrefix, namespace);
102 ActionConfig actionConfig = null;
103 for (String ext : resultsByExtension.keySet()) {
104 if (LOG.isDebugEnabled()) {
105 LOG.debug("Trying to locate unknown action template with extension ."+ext+" in directory "+pathPrefix);
106 }
107 String path = string(pathPrefix, actionName, "." , ext);
108 try {
109 if (locateTemplate(path) != null) {
110 actionConfig = buildActionConfig(path, namespace, actionName, resultsByExtension.get(ext));
111 break;
112 }
113 } catch (MalformedURLException e) {
114 LOG.warn("Unable to parse template path: "+path+", skipping...");
115 }
116 }
117 return actionConfig;
118 }
119
120 /*** Create a new ActionConfig in the default package, with the default interceptor stack and a single result */
121 protected ActionConfig buildActionConfig(String path, String namespace, String actionName, ResultTypeConfig resultTypeConfig) {
122 final PackageConfig pkg = configuration.getPackageConfig(defaultPackageName);
123 return new ActionConfig.Builder(defaultPackageName, "execute", ActionSupport.class.getName())
124 .addInterceptors(InterceptorBuilder.constructInterceptorReference(new InterceptorLocator() {
125 public Object getInterceptorConfig(String name) {
126 return pkg.getAllInterceptorConfigs().get(name);
127 }
128 }, pkg.getFullDefaultInterceptorRef(),
129 Collections.EMPTY_MAP, null, objectFactory))
130 .addResultConfig(new ResultConfig.Builder(Action.SUCCESS, resultTypeConfig.getClassName())
131 .addParams(resultTypeConfig.getParams())
132 .addParam(resultTypeConfig.getDefaultResultParam(), path)
133 .build())
134 .build();
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 (locateTemplate(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 (locateTemplate(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 ResultConfig resultConfig = new ResultConfig.Builder(resultCode, config.getClassName())
175 .addParams(config.getParams())
176 .addParam(config.getDefaultResultParam(), path)
177 .build();
178 try {
179 return objectFactory.buildResult(resultConfig, invocationContext.getContextMap());
180 } catch (Exception e) {
181 throw new XWorkException("Unable to build codebehind result", e, resultConfig);
182 }
183 }
184
185 protected String string(String... parts) {
186 StringBuilder sb = new StringBuilder();
187 for (String part : parts) {
188 sb.append(part);
189 }
190 return sb.toString();
191 }
192
193 protected String determinePath(String prefix, String ns) {
194 if (ns == null || "/".equals(ns)) {
195 ns = "";
196 }
197 if (ns.length() > 0) {
198 if (ns.charAt(0) == '/') {
199 ns = ns.substring(1);
200 }
201 if (ns.charAt(ns.length() - 1) != '/') {
202 ns += "/";
203 }
204 }
205 return prefix + ns;
206 }
207
208 URL locateTemplate(String path) throws MalformedURLException {
209 URL template = servletContext.getResource(path);
210 if (template != null) {
211 if (LOG.isDebugEnabled()) {
212 LOG.debug("Loaded template '" + path + "' from servlet context.");
213 }
214 } else {
215 template = ClassLoaderUtils.getResource(path, getClass());
216 if (template != null && LOG.isDebugEnabled()) {
217 LOG.debug("Loaded template '" + path + "' from class path.");
218 }
219 }
220 return template;
221 }
222
223
224 /***
225 * Not used
226 */
227 public Object handleUnknownActionMethod(Object action, String methodName) throws NoSuchMethodException {
228 throw new NoSuchMethodException();
229 }
230
231 }