mirror of
https://github.com/apache/struts.git
synced 2026-08-07 07:37:20 +00:00
Adding the codebehind plugin, which minimizes the amount of configuration needed for common cases (default results and templates with no Action)
WW-1515 git-svn-id: https://svn.apache.org/repos/asf/struts/struts2/trunk@476709 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>2.0.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-codebehind-plugin</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Struts 2 Codebehind Plugin</name>
|
||||
|
||||
<scm>
|
||||
<connection>scm:svn:http://svn.apache.org/repos/asf/struts/struts2/trunk/plugins/codebehind/</connection>
|
||||
<developerConnection>scm:svn:https://svn.apache.org/repos/asf/struts/struts2/trunk/plugins/codebehind/</developerConnection>
|
||||
<url>http://svn.apache.org/viewcvs.cgi/struts/struts2/trunk/plugins/codebehind/</url>
|
||||
</scm>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
<version>3.8.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mockobjects</groupId>
|
||||
<artifactId>mockobjects-core</artifactId>
|
||||
<version>0.09</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-mock</artifactId>
|
||||
<version>1.2.8</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>1.2.8</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<version>2.4</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>jsp-api</artifactId>
|
||||
<version>2.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
+212
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* $Id: DWRValidator.java 476642 2006-11-18 22:40:18Z mrdon $
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.struts2.codebehind;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import com.opensymphony.xwork2.Action;
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import com.opensymphony.xwork2.ObjectFactory;
|
||||
import com.opensymphony.xwork2.Result;
|
||||
import com.opensymphony.xwork2.UnknownHandler;
|
||||
import com.opensymphony.xwork2.XWorkException;
|
||||
import com.opensymphony.xwork2.config.Configuration;
|
||||
import com.opensymphony.xwork2.config.entities.ActionConfig;
|
||||
import com.opensymphony.xwork2.config.entities.PackageConfig;
|
||||
import com.opensymphony.xwork2.config.entities.ResultConfig;
|
||||
import com.opensymphony.xwork2.config.entities.ResultTypeConfig;
|
||||
import com.opensymphony.xwork2.config.providers.InterceptorBuilder;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
|
||||
public class CodebehindUnknownHandler implements UnknownHandler {
|
||||
|
||||
protected String defaultPackageName = "codebehind-default";
|
||||
protected ServletContext servletContext;
|
||||
protected Map<String,ResultTypeConfig> resultsByExtension = new HashMap<String,ResultTypeConfig>();
|
||||
protected String templatePathPrefix = "/";
|
||||
protected Configuration configuration;
|
||||
protected ObjectFactory objectFactory;
|
||||
|
||||
protected static final Log LOG = LogFactory.getLog(CodebehindUnknownHandler.class);
|
||||
|
||||
@Inject("struts.codebehind.defaultPackage")
|
||||
public void setDefaultPackage(String pkg) {
|
||||
this.defaultPackageName = pkg;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setConfiguration(Configuration config) {
|
||||
this.configuration = config;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setServletContext(ServletContext servletContext) {
|
||||
this.servletContext = servletContext;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setObjectFactory(ObjectFactory objectFactory) {
|
||||
this.objectFactory = objectFactory;
|
||||
}
|
||||
|
||||
protected Map<String,ResultTypeConfig> loadResultTypes(Configuration config) {
|
||||
Map<String,ResultTypeConfig> resultTypes = new LinkedHashMap<String,ResultTypeConfig>();
|
||||
PackageConfig parentPackage = config.getPackageConfig(defaultPackageName);
|
||||
Map<String,ResultTypeConfig> results = parentPackage.getAllResultTypeConfigs();
|
||||
|
||||
resultTypes.put("jsp", results.get("dispatcher"));
|
||||
resultTypes.put("vm", results.get("velocity"));
|
||||
resultTypes.put("ftl", results.get("freemarker"));
|
||||
return resultTypes;
|
||||
}
|
||||
|
||||
public ActionConfig handleUnknownAction(String namespace, String actionName)
|
||||
throws XWorkException {
|
||||
if (resultsByExtension == null) {
|
||||
resultsByExtension = loadResultTypes(configuration);
|
||||
}
|
||||
String pathPrefix = determinePath(templatePathPrefix, namespace);
|
||||
ActionConfig actionConfig = null;
|
||||
for (String ext : resultsByExtension.keySet()) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Trying to locate unknown action template with extension ."+ext+" in directory "+pathPrefix);
|
||||
}
|
||||
String path = string(pathPrefix, actionName, "." , ext);
|
||||
try {
|
||||
if (servletContext.getResource(path) != null) {
|
||||
actionConfig = buildActionConfig(path, namespace, actionName, resultsByExtension.get(ext));
|
||||
break;
|
||||
}
|
||||
} catch (MalformedURLException e) {
|
||||
LOG.warn("Unable to parse template path: "+path+", skipping...");
|
||||
}
|
||||
}
|
||||
return actionConfig;
|
||||
}
|
||||
|
||||
protected ActionConfig buildActionConfig(String path, String namespace, String actionName, ResultTypeConfig resultTypeConfig) {
|
||||
if (resultsByExtension == null) {
|
||||
resultsByExtension = loadResultTypes(configuration);
|
||||
}
|
||||
Map<String,ResultConfig> results = new HashMap<String,ResultConfig>();
|
||||
HashMap params = new HashMap();
|
||||
if (resultTypeConfig.getParams() != null) {
|
||||
params.putAll(resultTypeConfig.getParams());
|
||||
}
|
||||
params.put(resultTypeConfig.getDefaultResultParam(), path);
|
||||
|
||||
PackageConfig pkg = configuration.getPackageConfig(defaultPackageName);
|
||||
List interceptors = InterceptorBuilder.constructInterceptorReference(pkg, pkg.getFullDefaultInterceptorRef(),
|
||||
Collections.EMPTY_MAP, null, objectFactory);
|
||||
ResultConfig config = new ResultConfig(Action.SUCCESS, resultTypeConfig.getClazz(), params);
|
||||
results.put(Action.SUCCESS, config);
|
||||
return new ActionConfig("execute", ActionSupport.class.getName(), defaultPackageName, new HashMap(), results, interceptors);
|
||||
}
|
||||
|
||||
public Result handleUnknownResult(ActionContext actionContext, String actionName,
|
||||
ActionConfig actionConfig, String resultCode) throws XWorkException {
|
||||
|
||||
Result result = null;
|
||||
PackageConfig pkg = configuration.getPackageConfig(actionConfig.getPackageName());
|
||||
String ns = pkg.getNamespace();
|
||||
String pathPrefix = determinePath(templatePathPrefix, ns);
|
||||
|
||||
for (String ext : resultsByExtension.keySet()) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Trying to locate result with extension ."+ext+" in directory "+pathPrefix);
|
||||
}
|
||||
String path = string(pathPrefix, actionName, "-", resultCode, "." , ext);
|
||||
try {
|
||||
if (servletContext.getResource(path) != null) {
|
||||
result = buildResult(path, resultCode, resultsByExtension.get(ext), actionContext);
|
||||
break;
|
||||
}
|
||||
} catch (MalformedURLException e) {
|
||||
LOG.warn("Unable to parse template path: "+path+", skipping...");
|
||||
}
|
||||
|
||||
path = string(pathPrefix, actionName, "." , ext);
|
||||
try {
|
||||
if (servletContext.getResource(path) != null) {
|
||||
result = buildResult(path, resultCode, resultsByExtension.get(ext), actionContext);
|
||||
break;
|
||||
}
|
||||
} catch (MalformedURLException e) {
|
||||
LOG.warn("Unable to parse template path: "+path+", skipping...");
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected Result buildResult(String path, String resultCode, ResultTypeConfig config, ActionContext invocationContext) {
|
||||
String resultClass = config.getClazz();
|
||||
|
||||
Map<String,String> params = new LinkedHashMap<String,String>();
|
||||
if (config.getParams() != null) {
|
||||
params.putAll(config.getParams());
|
||||
}
|
||||
params.put(config.getDefaultResultParam(), path);
|
||||
|
||||
ResultConfig resultConfig = new ResultConfig(resultCode, resultClass, params);
|
||||
try {
|
||||
return objectFactory.buildResult(resultConfig, invocationContext.getContextMap());
|
||||
} catch (Exception e) {
|
||||
throw new XWorkException("Unable to build codebehind result", e, resultConfig);
|
||||
}
|
||||
}
|
||||
|
||||
protected String string(String... parts) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String part : parts) {
|
||||
sb.append(part);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
protected String determinePath(String prefix, String ns) {
|
||||
if (ns == null || "/".equals(ns)) {
|
||||
ns = "";
|
||||
}
|
||||
if (ns.length() > 0) {
|
||||
if (ns.charAt(0) == '/') {
|
||||
ns = ns.substring(1);
|
||||
}
|
||||
if (ns.charAt(ns.length() - 1) != '/') {
|
||||
ns += "/";
|
||||
}
|
||||
}
|
||||
return prefix + ns;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.0.dtd">
|
||||
|
||||
<struts>
|
||||
<bean type="com.opensymphony.xwork2.UnknownHandler" class="org.apache.struts2.codebehind.CodebehindUnknownHandler" />
|
||||
|
||||
<package name="codebehind-default" extends="struts-default">
|
||||
</package>
|
||||
</struts>
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* $Id: DWRValidator.java 476642 2006-11-18 22:40:18Z mrdon $
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.struts2.codebehind;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.apache.struts2.StrutsTestCase;
|
||||
import org.apache.struts2.config.NullResult;
|
||||
import org.apache.struts2.dispatcher.ServletDispatcherResult;
|
||||
|
||||
import com.mockobjects.dynamic.Mock;
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.ObjectFactory;
|
||||
import com.opensymphony.xwork2.Result;
|
||||
import com.opensymphony.xwork2.VoidResult;
|
||||
import com.opensymphony.xwork2.config.entities.ResultTypeConfig;
|
||||
|
||||
public class CodebehindUnknownHandlerTest extends StrutsTestCase {
|
||||
|
||||
CodebehindUnknownHandler handler;
|
||||
Mock mockServletContext;
|
||||
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
mockServletContext = new Mock(ServletContext.class);
|
||||
handler = new CodebehindUnknownHandler();
|
||||
handler.setConfiguration(configuration);
|
||||
handler.setObjectFactory(container.getInstance(ObjectFactory.class));
|
||||
handler.setServletContext((ServletContext)mockServletContext.proxy());
|
||||
|
||||
}
|
||||
|
||||
public void testBuildResult() {
|
||||
ActionContext ctx = new ActionContext(new HashMap());
|
||||
ResultTypeConfig config = new ResultTypeConfig("null", SomeResult.class.getName(), "location");
|
||||
|
||||
Result result = handler.buildResult("/foo.jsp", "success", config, ctx);
|
||||
assertNotNull(result);
|
||||
assertTrue(result instanceof SomeResult);
|
||||
assertEquals("/foo.jsp", ((SomeResult) result).location);
|
||||
|
||||
}
|
||||
|
||||
public void testString() {
|
||||
assertEquals("foo.bar.jim", handler.string("foo", ".", "bar", ".", "jim"));
|
||||
}
|
||||
|
||||
public void testDeterminePath() {
|
||||
assertEquals("/", handler.determinePath("/", ""));
|
||||
assertEquals("/", handler.determinePath("/", null));
|
||||
assertEquals("/", handler.determinePath("/", "/"));
|
||||
assertEquals("/foo/", handler.determinePath("/", "/foo"));
|
||||
assertEquals("/foo/", handler.determinePath("/", "/foo/"));
|
||||
assertEquals("/foo/", handler.determinePath("/", "foo"));
|
||||
}
|
||||
|
||||
public static class SomeResult implements Result {
|
||||
|
||||
public String location;
|
||||
public void setLocation(String loc) {
|
||||
this.location = loc;
|
||||
}
|
||||
|
||||
public void execute(ActionInvocation invocation) throws Exception {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,6 +19,7 @@
|
||||
</scm>
|
||||
|
||||
<modules>
|
||||
<module>codebehind</module>
|
||||
<module>config-browser</module>
|
||||
<module>jasperreports</module>
|
||||
<module>jfreechart</module>
|
||||
|
||||
Reference in New Issue
Block a user