View Javadoc

1   /*
2    * $Id: CodebehindUnknownHandler.java 651946 2008-04-27 13:41:38Z apetrelli $
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  
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); // recurse package hiearchy
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 }