Author: mrdon Date: Sat Nov 18 21:03:10 2006 New Revision: 476709 URL: http://svn.apache.org/viewvc?view=rev&rev=476709 Log: Adding the codebehind plugin, which minimizes the amount of configuration needed for common cases (default results and templates with no Action) WW-1515
Added: struts/struts2/trunk/plugins/codebehind/ struts/struts2/trunk/plugins/codebehind/pom.xml struts/struts2/trunk/plugins/codebehind/src/ struts/struts2/trunk/plugins/codebehind/src/main/ struts/struts2/trunk/plugins/codebehind/src/main/java/ struts/struts2/trunk/plugins/codebehind/src/main/java/org/ struts/struts2/trunk/plugins/codebehind/src/main/java/org/apache/ struts/struts2/trunk/plugins/codebehind/src/main/java/org/apache/struts2/ struts/struts2/trunk/plugins/codebehind/src/main/java/org/apache/struts2/codebehind/ struts/struts2/trunk/plugins/codebehind/src/main/java/org/apache/struts2/codebehind/CodebehindUnknownHandler.java struts/struts2/trunk/plugins/codebehind/src/main/resources/ struts/struts2/trunk/plugins/codebehind/src/main/resources/struts-plugin.xml struts/struts2/trunk/plugins/codebehind/src/test/ struts/struts2/trunk/plugins/codebehind/src/test/java/ struts/struts2/trunk/plugins/codebehind/src/test/java/org/ struts/struts2/trunk/plugins/codebehind/src/test/java/org/apache/ struts/struts2/trunk/plugins/codebehind/src/test/java/org/apache/struts2/ struts/struts2/trunk/plugins/codebehind/src/test/java/org/apache/struts2/codebehind/ struts/struts2/trunk/plugins/codebehind/src/test/java/org/apache/struts2/codebehind/CodebehindUnknownHandlerTest.java Modified: struts/struts2/trunk/plugins/pom.xml Added: struts/struts2/trunk/plugins/codebehind/pom.xml URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/codebehind/pom.xml?view=auto&rev=476709 ============================================================================== --- struts/struts2/trunk/plugins/codebehind/pom.xml (added) +++ struts/struts2/trunk/plugins/codebehind/pom.xml Sat Nov 18 21:03:10 2006 @@ -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> Added: struts/struts2/trunk/plugins/codebehind/src/main/java/org/apache/struts2/codebehind/CodebehindUnknownHandler.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/codebehind/src/main/java/org/apache/struts2/codebehind/CodebehindUnknownHandler.java?view=auto&rev=476709 ============================================================================== --- struts/struts2/trunk/plugins/codebehind/src/main/java/org/apache/struts2/codebehind/CodebehindUnknownHandler.java (added) +++ struts/struts2/trunk/plugins/codebehind/src/main/java/org/apache/struts2/codebehind/CodebehindUnknownHandler.java Sat Nov 18 21:03:10 2006 @@ -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; + } + +} Added: struts/struts2/trunk/plugins/codebehind/src/main/resources/struts-plugin.xml URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/codebehind/src/main/resources/struts-plugin.xml?view=auto&rev=476709 ============================================================================== --- struts/struts2/trunk/plugins/codebehind/src/main/resources/struts-plugin.xml (added) +++ struts/struts2/trunk/plugins/codebehind/src/main/resources/struts-plugin.xml Sat Nov 18 21:03:10 2006 @@ -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> Added: struts/struts2/trunk/plugins/codebehind/src/test/java/org/apache/struts2/codebehind/CodebehindUnknownHandlerTest.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/codebehind/src/test/java/org/apache/struts2/codebehind/CodebehindUnknownHandlerTest.java?view=auto&rev=476709 ============================================================================== --- struts/struts2/trunk/plugins/codebehind/src/test/java/org/apache/struts2/codebehind/CodebehindUnknownHandlerTest.java (added) +++ struts/struts2/trunk/plugins/codebehind/src/test/java/org/apache/struts2/codebehind/CodebehindUnknownHandlerTest.java Sat Nov 18 21:03:10 2006 @@ -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 { + } + + } + +} Modified: struts/struts2/trunk/plugins/pom.xml URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/pom.xml?view=diff&rev=476709&r1=476708&r2=476709 ============================================================================== --- struts/struts2/trunk/plugins/pom.xml (original) +++ struts/struts2/trunk/plugins/pom.xml Sat Nov 18 21:03:10 2006 @@ -19,6 +19,7 @@ </scm> <modules> + <module>codebehind</module> <module>config-browser</module> <module>jasperreports</module> <module>jfreechart</module>