Author: mrdon Date: Fri Oct 12 07:07:52 2007 New Revision: 584166 URL: http://svn.apache.org/viewvc?rev=584166&view=rev Log: Moving zero config code into codebehind plugin, minor fix to showcase WW-2247
Added: struts/struts2/trunk/plugins/codebehind/src/main/java/org/apache/struts2/config/ struts/struts2/trunk/plugins/codebehind/src/main/java/org/apache/struts2/config/ClasspathPackageProvider.java struts/struts2/trunk/plugins/codebehind/src/main/java/org/apache/struts2/config/Namespace.java - copied unchanged from r584160, struts/struts2/trunk/core/src/main/java/org/apache/struts2/config/Namespace.java struts/struts2/trunk/plugins/codebehind/src/main/java/org/apache/struts2/config/ParentPackage.java - copied unchanged from r584160, struts/struts2/trunk/core/src/main/java/org/apache/struts2/config/ParentPackage.java struts/struts2/trunk/plugins/codebehind/src/main/java/org/apache/struts2/config/Result.java - copied unchanged from r584160, struts/struts2/trunk/core/src/main/java/org/apache/struts2/config/Result.java struts/struts2/trunk/plugins/codebehind/src/main/java/org/apache/struts2/config/Results.java - copied unchanged from r584160, struts/struts2/trunk/core/src/main/java/org/apache/struts2/config/Results.java struts/struts2/trunk/plugins/codebehind/src/test/java/org/apache/struts2/config/ struts/struts2/trunk/plugins/codebehind/src/test/java/org/apache/struts2/config/ClasspathPackageProviderTest.java struts/struts2/trunk/plugins/codebehind/src/test/java/org/apache/struts2/config/CustomNamespaceAction.java - copied unchanged from r584160, struts/struts2/trunk/core/src/test/java/org/apache/struts2/config/CustomNamespaceAction.java struts/struts2/trunk/plugins/codebehind/src/test/java/org/apache/struts2/config/CustomParentPackageAction.java - copied unchanged from r584160, struts/struts2/trunk/core/src/test/java/org/apache/struts2/config/CustomParentPackageAction.java struts/struts2/trunk/plugins/codebehind/src/test/java/org/apache/struts2/config/cltest/ - copied from r584160, struts/struts2/trunk/core/src/test/java/org/apache/struts2/config/cltest/ Removed: struts/struts2/trunk/core/src/main/java/org/apache/struts2/config/ClasspathConfigurationProvider.java struts/struts2/trunk/core/src/main/java/org/apache/struts2/config/Namespace.java struts/struts2/trunk/core/src/main/java/org/apache/struts2/config/ParentPackage.java struts/struts2/trunk/core/src/main/java/org/apache/struts2/config/Result.java struts/struts2/trunk/core/src/main/java/org/apache/struts2/config/Results.java struts/struts2/trunk/core/src/test/java/org/apache/struts2/config/ClasspathConfigurationProviderTest.java struts/struts2/trunk/core/src/test/java/org/apache/struts2/config/CustomNamespaceAction.java struts/struts2/trunk/core/src/test/java/org/apache/struts2/config/CustomParentPackageAction.java struts/struts2/trunk/core/src/test/java/org/apache/struts2/config/cltest/ Modified: struts/struts2/trunk/apps/showcase/src/main/resources/struts.xml struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/Dispatcher.java struts/struts2/trunk/plugins/codebehind/src/main/resources/struts-plugin.xml struts/struts2/trunk/plugins/codebehind/src/test/java/org/apache/struts2/codebehind/CodebehindUnknownHandlerTest.java Modified: struts/struts2/trunk/apps/showcase/src/main/resources/struts.xml URL: http://svn.apache.org/viewvc/struts/struts2/trunk/apps/showcase/src/main/resources/struts.xml?rev=584166&r1=584165&r2=584166&view=diff ============================================================================== --- struts/struts2/trunk/apps/showcase/src/main/resources/struts.xml (original) +++ struts/struts2/trunk/apps/showcase/src/main/resources/struts.xml Fri Oct 12 07:07:52 2007 @@ -67,6 +67,8 @@ </interceptor-stack> </interceptors> + <default-action-ref name="showcase" /> + <action name="showcase"> <result>showcase.jsp</result> </action> Modified: struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/Dispatcher.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/Dispatcher.java?rev=584166&r1=584165&r2=584166&view=diff ============================================================================== --- struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/Dispatcher.java (original) +++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/Dispatcher.java Fri Oct 12 07:07:52 2007 @@ -39,12 +39,9 @@ import org.apache.struts2.StrutsConstants; import org.apache.struts2.StrutsStatics; import org.apache.struts2.config.BeanSelectionProvider; -import org.apache.struts2.config.ClasspathConfigurationProvider; import org.apache.struts2.config.DefaultPropertiesProvider; import org.apache.struts2.config.LegacyPropertiesConfigurationProvider; import org.apache.struts2.config.StrutsXmlConfigurationProvider; -import org.apache.struts2.config.ClasspathConfigurationProvider.ClasspathPageLocator; -import org.apache.struts2.config.ClasspathConfigurationProvider.PageLocator; import org.apache.struts2.dispatcher.mapper.ActionMapping; import org.apache.struts2.dispatcher.multipart.MultiPartRequest; import org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper; @@ -302,19 +299,6 @@ } } - private void init_ZeroConfiguration() { - String packages = initParams.get("actionPackages"); - if (packages != null) { - String[] names = packages.split("\\s*[,]\\s*"); - // Initialize the classloader scanner with the configured packages - if (names.length > 0) { - ClasspathConfigurationProvider provider = new ClasspathConfigurationProvider(names); - provider.setPageLocator(new ServletContextPageLocator(servletContext)); - configurationManager.addConfigurationProvider(provider); - } - } - } - private void init_CustomConfigurationProviders() { String configProvs = initParams.get("configProviders"); if (configProvs != null) { @@ -434,7 +418,6 @@ init_DefaultProperties(); // [1] init_TraditionalXmlConfigurations(); // [2] init_LegacyStrutsProperties(); // [3] - init_ZeroConfiguration(); // [4] init_CustomConfigurationProviders(); // [5] init_MethodConfigurationProvider(); init_FilterInitParameters() ; // [6] @@ -757,32 +740,7 @@ } } - /** - * Search classpath for a page. - */ - private final class ServletContextPageLocator implements PageLocator { - private final ServletContext context; - private ClasspathPageLocator classpathPageLocator = new ClasspathPageLocator(); - - private ServletContextPageLocator(ServletContext context) { - this.context = context; - } - - public URL locate(String path) { - URL url = null; - try { - url = context.getResource(path); - if (url == null) { - url = classpathPageLocator.locate(path); - } - } catch (MalformedURLException e) { - if (LOG.isDebugEnabled()) { - LOG.debug("Unable to resolve path "+path+" against the servlet context"); - } - } - return url; - } - } + /** * Provide an accessor class for static XWork utility. Added: struts/struts2/trunk/plugins/codebehind/src/main/java/org/apache/struts2/config/ClasspathPackageProvider.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/codebehind/src/main/java/org/apache/struts2/config/ClasspathPackageProvider.java?rev=584166&view=auto ============================================================================== --- struts/struts2/trunk/plugins/codebehind/src/main/java/org/apache/struts2/config/ClasspathPackageProvider.java (added) +++ struts/struts2/trunk/plugins/codebehind/src/main/java/org/apache/struts2/config/ClasspathPackageProvider.java Fri Oct 12 07:07:52 2007 @@ -0,0 +1,570 @@ +/* + * $Id: ClasspathPackageProvider.java 582626 2007-10-07 13:26:12Z 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.config; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Modifier; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import javax.servlet.ServletContext; + +import com.opensymphony.xwork2.Action; +import com.opensymphony.xwork2.config.Configuration; +import com.opensymphony.xwork2.config.ConfigurationException; +import com.opensymphony.xwork2.config.ConfigurationProvider; +import com.opensymphony.xwork2.config.PackageProvider; +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.inject.ContainerBuilder; +import com.opensymphony.xwork2.inject.Inject; +import com.opensymphony.xwork2.util.ClassLoaderUtil; +import com.opensymphony.xwork2.util.ResolverUtil; +import com.opensymphony.xwork2.util.TextUtils; +import com.opensymphony.xwork2.util.ResolverUtil.ClassTest; +import com.opensymphony.xwork2.util.location.LocatableProperties; +import com.opensymphony.xwork2.util.logging.Logger; +import com.opensymphony.xwork2.util.logging.LoggerFactory; + +/** + * ClasspathPackageProvider loads the configuration + * by scanning the classpath or selected packages for Action classes. + * <p> + * This provider is only invoked if one or more action packages are passed to the dispatcher, + * usually from the web.xml. + * Configurations are created for objects that either implement Action or have classnames that end with "Action". + */ +public class ClasspathPackageProvider implements PackageProvider { + + /** + * The default page prefix (or "path"). + * Some applications may place pages under "/WEB-INF" as an extreme security precaution. + */ + private static final String DEFAULT_PAGE_PREFIX = "struts.configuration.classpath.defaultPagePrefix"; + + /** + * The default page prefix (none). + */ + private String defaultPagePrefix = ""; + + /** + * The default page extension, to use in place of ".jsp". + */ + private static final String DEFAULT_PAGE_EXTENSION = "struts.configuration.classpath.defaultPageExtension"; + + /** + * The defacto default page extension, usually associated with JavaServer Pages. + */ + private String defaultPageExtension = ".jsp"; + + /** + * A setting to indicate a custom default parent package, + * to use in place of "struts-default". + */ + private static final String DEFAULT_PARENT_PACKAGE = "struts.configuration.classpath.defaultParentPackage"; + + /** + * Name of the framework's default configuration package, + * that application configuration packages automatically inherit. + */ + private String defaultParentPackage = "struts-default"; + + /** + * The default page prefix (or "path"). + * Some applications may place pages under "/WEB-INF" as an extreme security precaution. + */ + private static final String FORCE_LOWER_CASE = "struts.configuration.classpath.forceLowerCase"; + + /** + * Whether to use a lowercase letter as the initial letter of an action. + * If false, actions will retain the initial uppercase letter from the Action class. + * (<code>view.action</code> (true) versus <code>View.action</code> (false)). + */ + private boolean forceLowerCase = true; + + /** + * Default suffix that can be used to indicate POJO "Action" classes. + */ + private static final String ACTION = "Action"; + + /** + * Helper class to scan class path for server pages. + */ + private PageLocator pageLocator = new ClasspathPageLocator(); + + /** + * Flag to indicate the packages have been loaded. + * + * @see #loadPackages + * @see #needsReload + */ + private boolean initialized = false; + + /** + * The package configurations for scanned Actions. + * + * @see #loadPackageConfig + */ + private Map<String,PackageConfig> loadedPackageConfigs = new HashMap<String,PackageConfig>(); + + /** + * Logging instance for this class. + */ + private static final Logger LOG = LoggerFactory.getLogger(ClasspathPackageProvider.class); + + /** + * The XWork Configuration for this application. + * + * @see #init + */ + private Configuration configuration; + + private String actionPackages; + + private ServletContext servletContext; + + /** + * Create instance utilizing a list of packages to scan for Action classes. + * + * @param pkgs List of pacaktges to scan for Action Classes. + */ + public ClasspathPackageProvider() { + } + + /** + * PageLocator defines a locate method that can be used to discover server pages. + */ + public static interface PageLocator { + public URL locate(String path); + } + + /** + * ClasspathPathLocator searches the classpath for server pages. + */ + public static class ClasspathPageLocator implements PageLocator { + public URL locate(String path) { + return ClassLoaderUtil.getResource(path, getClass()); + } + } + + @Inject("actionPackages") + public void setActionPackages(String packages) { + this.actionPackages = packages; + } + + public void setServletContext(ServletContext ctx) { + this.servletContext = ctx; + } + + /** + * Register a default parent package for the actions. + * + * @param defaultParentPackage the new defaultParentPackage + */ + @Inject(value=DEFAULT_PARENT_PACKAGE, required=false) + public void setDefaultParentPackage(String defaultParentPackage) { + this.defaultParentPackage = defaultParentPackage; + } + + /** + * Register a default page extension to use when locating pages. + * + * @param defaultPageExtension the new defaultPageExtension + */ + @Inject(value=DEFAULT_PAGE_EXTENSION, required=false) + public void setDefaultPageExtension(String defaultPageExtension) { + this.defaultPageExtension = defaultPageExtension; + } + + /** + * Reigster a default page prefix to use when locating pages. + * + * @param defaultPagePrefix the defaultPagePrefix to set + */ + @Inject(value=DEFAULT_PAGE_PREFIX, required=false) + public void setDefaultPagePrefix(String defaultPagePrefix) { + this.defaultPagePrefix = defaultPagePrefix; + } + + /** + * Whether to use a lowercase letter as the initial letter of an action. + * + * @param force If false, actions will retain the initial uppercase letter from the Action class. + * (<code>view.action</code> (true) versus <code>View.action</code> (false)). + */ + @Inject(value=FORCE_LOWER_CASE, required=false) + public void setForceLowerCase(String force) { + this.forceLowerCase = "true".equals(force); + } + + /** + * Register a PageLocation to use to scan for server pages. + * + * @param locator + */ + public void setPageLocator(PageLocator locator) { + this.pageLocator = locator; + } + + /** + * Scan a list of packages for Action classes. + * + * This method loads classes that implement the Action interface + * or have a class name that ends with the letters "Action". + * + * @param pkgs A list of packages to load + * @see #processActionClass + */ + protected void loadPackages(String[] pkgs) { + + ResolverUtil<Class> resolver = new ResolverUtil<Class>(); + resolver.find(new ClassTest() { + // Match Action implementations and classes ending with "Action" + public boolean matches(Class type) { + // TODO: should also find annotated classes + return (Action.class.isAssignableFrom(type) || + type.getSimpleName().endsWith("Action")); + } + + }, pkgs); + + Set<? extends Class<? extends Class>> actionClasses = resolver.getClasses(); + for (Object obj : actionClasses) { + Class cls = (Class) obj; + if (!Modifier.isAbstract(cls.getModifiers())) { + processActionClass(cls, pkgs); + } + } + + for (String key : loadedPackageConfigs.keySet()) { + configuration.addPackageConfig(key, loadedPackageConfigs.get(key)); + } + } + + /** + * Create a default action mapping for a class instance. + * + * The namespace annotation is honored, if found, otherwise + * the Java package is converted into the namespace + * by changing the dots (".") to slashes ("/"). + * + * @param cls Action or POJO instance to process + * @param pkgs List of packages that were scanned for Actions + */ + protected void processActionClass(Class cls, String[] pkgs) { + String name = cls.getName(); + String actionPackage = cls.getPackage().getName(); + String actionNamespace = null; + String actionName = null; + for (String pkg : pkgs) { + if (name.startsWith(pkg)) { + if (LOG.isDebugEnabled()) { + LOG.debug("ClasspathPackageProvider: Processing class "+name); + } + name = name.substring(pkg.length() + 1); + + actionNamespace = ""; + actionName = name; + int pos = name.lastIndexOf('.'); + if (pos > -1) { + actionNamespace = "/" + name.substring(0, pos).replace('.','/'); + actionName = name.substring(pos+1); + } + break; + } + } + + PackageConfig pkgConfig = loadPackageConfig(actionNamespace, actionPackage, cls); + + // In case the package changed due to namespace annotation processing + if (!actionPackage.equals(pkgConfig.getName())) { + actionPackage = pkgConfig.getName(); + } + + Annotation annotation = cls.getAnnotation(ParentPackage.class); + if (annotation != null) { + String parent = ((ParentPackage)annotation).value(); + PackageConfig parentPkg = configuration.getPackageConfig(parent); + if (parentPkg == null) { + throw new ConfigurationException("ClasspathPackageProvider: Unable to locate parent package "+parent, annotation); + } + pkgConfig.addParent(parentPkg); + + if (!TextUtils.stringSet(pkgConfig.getNamespace()) && TextUtils.stringSet(parentPkg.getNamespace())) { + pkgConfig.setNamespace(parentPkg.getNamespace()); + } + } + + // Truncate Action suffix if found + if (actionName.endsWith(ACTION)) { + actionName = actionName.substring(0, actionName.length() - ACTION.length()); + } + + // Force initial letter of action to lowercase, if desired + if ((forceLowerCase) && (actionName.length() > 1)) { + int lowerPos = actionName.lastIndexOf('/') + 1; + StringBuilder sb = new StringBuilder(); + sb.append(actionName.substring(0, lowerPos)); + sb.append(Character.toLowerCase(actionName.charAt(lowerPos))); + sb.append(actionName.substring(lowerPos + 1)); + actionName = sb.toString(); + } + + ActionConfig actionConfig = new ActionConfig(); + actionConfig.setClassName(cls.getName()); + actionConfig.setPackageName(actionPackage); + + actionConfig.setResults(new ResultMap<String,ResultConfig>(cls, actionName, pkgConfig)); + pkgConfig.addActionConfig(actionName, actionConfig); + } + + /** + * Finds or creates the package configuration for an Action class. + * + * The namespace annotation is honored, if found, + * and the namespace is checked for a parent configuration. + * + * @param actionNamespace The configuration namespace + * @param actionPackage The Java package containing our Action classes + * @param actionClass The Action class instance + * @return PackageConfig object for the Action class + */ + protected PackageConfig loadPackageConfig(String actionNamespace, String actionPackage, Class actionClass) { + PackageConfig parent = null; + + if (actionClass != null) { + Namespace ns = (Namespace) actionClass.getAnnotation(Namespace.class); + if (ns != null) { + parent = loadPackageConfig(actionNamespace, actionPackage, null); + actionNamespace = ns.value(); + actionPackage = actionClass.getName(); + } + } + + PackageConfig pkgConfig = loadedPackageConfigs.get(actionPackage); + if (pkgConfig == null) { + pkgConfig = new PackageConfig(); + pkgConfig.setName(actionPackage); + + if (parent == null) { + parent = configuration.getPackageConfig(defaultParentPackage); + } + + if (parent == null) { + throw new ConfigurationException("ClasspathPackageProvider: Unable to locate default parent package: " + + defaultParentPackage); + } + pkgConfig.addParent(parent); + + pkgConfig.setNamespace(actionNamespace); + + loadedPackageConfigs.put(actionPackage, pkgConfig); + } + return pkgConfig; + } + + /** + * Default destructor. Override to provide behavior. + */ + public void destroy() { + + } + + /** + * Register this application's configuration. + * + * @param config The configuration for this application. + */ + public void init(Configuration config) { + this.configuration = config; + } + + /** + * Clears and loads the list of packages registered at construction. + * + * @throws ConfigurationException + */ + public void loadPackages() throws ConfigurationException { + loadedPackageConfigs.clear(); + if (actionPackages != null) { + String[] names = actionPackages.split("\\s*[,]\\s*"); + // Initialize the classloader scanner with the configured packages + if (names.length > 0) { + setPageLocator(new ServletContextPageLocator(servletContext)); + } + loadPackages(names); + } + initialized = true; + } + + /** + * Indicates whether the packages have been initialized. + * + * @return True if the packages have been initialized + */ + public boolean needsReload() { + return !initialized; + } + + /** + * Creates ResultConfig objects from result annotations, + * and if a result isn't found, creates it on the fly. + */ + class ResultMap<K,V> extends HashMap<K,V> { + private Class actionClass; + private String actionName; + private PackageConfig pkgConfig; + + public ResultMap(Class actionClass, String actionName, PackageConfig pkgConfig) { + this.actionClass = actionClass; + this.actionName = actionName; + this.pkgConfig = pkgConfig; + + // check if any annotations are around + while (!actionClass.getName().equals(Object.class.getName())) { + //noinspection unchecked + Results results = (Results) actionClass.getAnnotation(Results.class); + if (results != null) { + // first check here... + for (int i = 0; i < results.value().length; i++) { + Result result = results.value()[i]; + ResultConfig config = createResultConfig(result); + put((K)config.getName(), (V)config); + } + } + + // what about a single Result annotation? + Result result = (Result) actionClass.getAnnotation(Result.class); + if (result != null) { + ResultConfig config = createResultConfig(result); + put((K)config.getName(), (V)config); + } + + actionClass = actionClass.getSuperclass(); + } + } + + /** + * Extracts result name and value and calls [EMAIL PROTECTED] #createResultConfig}. + * + * @param result Result annotation reference representing result type to create + * @return New or cached ResultConfig object for result + */ + protected ResultConfig createResultConfig(Result result) { + Class<? extends Object> cls = result.type(); + if (cls == NullResult.class) { + cls = null; + } + return createResultConfig(result.name(), cls, result.value(), createParameterMap(result.params())); + } + + protected Map<String, String> createParameterMap(String[] parms) { + Map<String, String> map = new HashMap<String, String>(); + int subtract = parms.length % 2; + if(subtract != 0) { + LOG.warn("Odd number of result parameters key/values specified. The final one will be ignored."); + } + for (int i = 0; i < parms.length - subtract; i++) { + String key = parms[i++]; + String value = parms[i]; + map.put(key, value); + if(LOG.isDebugEnabled()) { + LOG.debug("Adding parmeter["+key+":"+value+"] to result."); + } + } + return map; + } + + /** + * Creates a default ResultConfig, + * using either the resultClass or the default ResultType for configuration package + * associated this ResultMap class. + * + * @param key The result type name + * @param resultClass The class for the result type + * @param location Path to the resource represented by this type + * @return A ResultConfig for key mapped to location + */ + private ResultConfig createResultConfig(Object key, Class<? extends Object> resultClass, + String location, + Map<? extends Object,? extends Object > configParams) { + if (resultClass == null) { + String defaultResultType = pkgConfig.getFullDefaultResultType(); + ResultTypeConfig resultType = pkgConfig.getAllResultTypeConfigs().get(defaultResultType); + configParams = resultType.getParams(); + String className = resultType.getClazz(); + try { + resultClass = ClassLoaderUtil.loadClass(className, getClass()); + } catch (ClassNotFoundException ex) { + throw new ConfigurationException("ClasspathPackageProvider: Unable to locate result class "+className, actionClass); + } + } + + String defaultParam; + try { + defaultParam = (String) resultClass.getField("DEFAULT_PARAM").get(null); + } catch (Exception e) { + // not sure why this happened, but let's just use a sensible choice + defaultParam = "location"; + } + + HashMap params = new HashMap(); + if (configParams != null) { + params.putAll(configParams); + } + + params.put(defaultParam, location); + return new ResultConfig((String) key, resultClass.getName(), params); + } + } + + /** + * Search classpath for a page. + */ + private final class ServletContextPageLocator implements PageLocator { + private final ServletContext context; + private ClasspathPageLocator classpathPageLocator = new ClasspathPageLocator(); + + private ServletContextPageLocator(ServletContext context) { + this.context = context; + } + + public URL locate(String path) { + URL url = null; + try { + url = context.getResource(path); + if (url == null) { + url = classpathPageLocator.locate(path); + } + } catch (MalformedURLException e) { + if (LOG.isDebugEnabled()) { + LOG.debug("Unable to resolve path "+path+" against the servlet context"); + } + } + return url; + } + } +} Modified: 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?rev=584166&r1=584165&r2=584166&view=diff ============================================================================== --- struts/struts2/trunk/plugins/codebehind/src/main/resources/struts-plugin.xml (original) +++ struts/struts2/trunk/plugins/codebehind/src/main/resources/struts-plugin.xml Fri Oct 12 07:07:52 2007 @@ -28,6 +28,7 @@ <struts> <bean type="com.opensymphony.xwork2.UnknownHandler" class="org.apache.struts2.codebehind.CodebehindUnknownHandler" /> + <bean type="com.opensymphony.xwork2.config.PackageProvider" name="codebehind" class="org.apache.struts2.config.ClasspathPackageProvider" /> <constant name="struts.codebehind.pathPrefix" value="/"/> <constant name="struts.codebehind.defaultPackage" value="codebehind-default"/> Modified: 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?rev=584166&r1=584165&r2=584166&view=diff ============================================================================== --- struts/struts2/trunk/plugins/codebehind/src/test/java/org/apache/struts2/codebehind/CodebehindUnknownHandlerTest.java (original) +++ struts/struts2/trunk/plugins/codebehind/src/test/java/org/apache/struts2/codebehind/CodebehindUnknownHandlerTest.java Fri Oct 12 07:07:52 2007 @@ -22,6 +22,7 @@ import java.net.MalformedURLException; import java.net.URL; +import java.util.Collections; import java.util.HashMap; import javax.servlet.ServletContext; @@ -34,9 +35,11 @@ import com.mockobjects.dynamic.Mock; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionInvocation; +import com.opensymphony.xwork2.ActionProxyFactory; import com.opensymphony.xwork2.ObjectFactory; import com.opensymphony.xwork2.Result; import com.opensymphony.xwork2.config.entities.ResultTypeConfig; +import com.opensymphony.xwork2.util.XWorkTestCaseHelper; public class CodebehindUnknownHandlerTest extends StrutsTestCase { @@ -44,7 +47,11 @@ Mock mockServletContext; public void setUp() throws Exception { - super.setUp(); + configurationManager = XWorkTestCaseHelper.setUp(); + configuration = configurationManager.getConfiguration(); + container = configuration.getContainer(); + actionProxyFactory = container.getInstance(ActionProxyFactory.class); + initDispatcher(Collections.singletonMap("actionPackages", "foo.bar")); mockServletContext = new Mock(ServletContext.class); handler = new CodebehindUnknownHandler("codebehind-default", configuration); handler.setPathPrefix("/"); Added: struts/struts2/trunk/plugins/codebehind/src/test/java/org/apache/struts2/config/ClasspathPackageProviderTest.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/codebehind/src/test/java/org/apache/struts2/config/ClasspathPackageProviderTest.java?rev=584166&view=auto ============================================================================== --- struts/struts2/trunk/plugins/codebehind/src/test/java/org/apache/struts2/config/ClasspathPackageProviderTest.java (added) +++ struts/struts2/trunk/plugins/codebehind/src/test/java/org/apache/struts2/config/ClasspathPackageProviderTest.java Fri Oct 12 07:07:52 2007 @@ -0,0 +1,103 @@ +/* + * $Id: ClasspathPackageProviderTest.java 501717 2007-01-31 03:51:11Z 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.config; + +import java.util.Map; + +import org.apache.struts2.dispatcher.ServletDispatcherResult; + +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.impl.DefaultConfiguration; + +import junit.framework.TestCase; + +public class ClasspathPackageProviderTest extends TestCase { + + ClasspathPackageProvider provider; + Configuration config; + + public void setUp() { + provider = new ClasspathPackageProvider(); + provider.setActionPackages("org.apache.struts2.config"); + config = new DefaultConfiguration(); + PackageConfig strutsDefault = new PackageConfig("struts-default"); + strutsDefault.addResultTypeConfig(new ResultTypeConfig("dispatcher", ServletDispatcherResult.class.getName(), "location")); + strutsDefault.setDefaultResultType("dispatcher"); + config.addPackageConfig("struts-default", strutsDefault); + PackageConfig customPackage = new PackageConfig("custom-package"); + customPackage.setNamespace("/custom"); + config.addPackageConfig("custom-package", customPackage); + provider.init(config); + provider.loadPackages(); + } + + public void testFoundRootPackages() { + assertEquals(5, config.getPackageConfigs().size()); + PackageConfig pkg = config.getPackageConfig("org.apache.struts2.config"); + assertNotNull(pkg); + Map configs = pkg.getActionConfigs(); + assertNotNull(configs); + // assertEquals(1, configs.size()); + ActionConfig actionConfig = (ActionConfig) configs.get("customParentPackage"); + assertNotNull(actionConfig); + } + + public void testParentPackage() { + PackageConfig pkg = config.getPackageConfig("org.apache.struts2.config"); + // assertEquals(2, pkg.getParents().size()); + Map configs = pkg.getActionConfigs(); + ActionConfig config = (ActionConfig) configs.get("customParentPackage"); + assertNotNull(config); + assertEquals("/custom", pkg.getNamespace()); + } + + public void testCustomNamespace() { + PackageConfig pkg = config.getPackageConfig("org.apache.struts2.config.CustomNamespaceAction"); + Map configs = pkg.getAllActionConfigs(); + // assertEquals(2, configs.size()); + ActionConfig config = (ActionConfig) configs.get("customNamespace"); + assertEquals(config.getPackageName(), pkg.getName()); + assertEquals(1, pkg.getParents().size()); + assertNotNull(config); + assertEquals("/mynamespace", pkg.getNamespace()); + ActionConfig ac = (ActionConfig) configs.get("customParentPackage"); + assertNotNull(ac); + } + + public void testResultAnnotations() { + PackageConfig pkg = config.getPackageConfig("org.apache.struts2.config.cltest"); + assertEquals("/cltest", pkg.getNamespace()); + ActionConfig acfg = pkg.getActionConfigs().get("twoResult"); + assertNotNull(acfg); + assertEquals(3, acfg.getResults().size()); + } + + public void testActionImplementation() { + PackageConfig pkg = config.getPackageConfig("org.apache.struts2.config.cltest"); + assertEquals("/cltest", pkg.getNamespace()); + ActionConfig acfg = pkg.getActionConfigs().get("actionImpl"); + assertNotNull(acfg); + } +}