View Javadoc

1   /*
2    * $Id: CodebehindUnknownHandler.java 519452 2007-03-17 21:50:09Z mrdon $
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
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 }