Yes, something like that. But I think i can be done in a hackish way without much change. Really it is the conventions plugin that is at fault, or rather a lack of convention regarding sharing configuration that aught to be standardized.
The beans and constants are currently scoped globally, just inside the <struts></struts> the beans in struts2-conventions-plugin struts-plugin.xml file can only be set once. Consider the struts2-rest plugin, at a quick glance of the setup documentation it is clear that it wants to impose it's own conventions: https://cwiki.apache.org/confluence/display/WW/REST+Plugin you will see a number of blocks such as: <constant name="struts.convention.action.suffix" value="Controller"/> <constant name="struts.convention.action.mapAllMatches" value="true"/> <constant name="struts.convention.default.parent.package" value= "rest-default"/> <constant name="struts.convention.package.locators" value="example"/> Which are required in the setup. This isn't as simple as it aught to be, there should be a number of packages defined in the rest plugins struts-plugin.xml and by extending that get the most typical configurations (obviously every configuration can't be known but a couple choices wouldn't be bad). Is it reasonable for people to be intimately familiar with the conventions configuration such that they would know how to configure the rest plugin? As it stands this seems to be the case but in terms of user experience, it's a bit of a pain and if you want both your conventions AND the rest plugin, you find yourself being stuck (like an under-inflated balloon animal, you can choose to have the head inflated of the tail, but not both). This is one possible way to solve the issue: - Create a new interceptor called "PackageConfigurationInterceptor"; since interceptors are instantiated once per package they have the scope that I would expect. - When using conventions scan for the existence of this interceptor, if found use it's beans and constants in place of the global ones. ======================================= package com.kenmcwilliams.struts.config; public class ConventionsPackageConfigInterceptor extends PackageConfigInterceptor { public ConventionsPackageConfigInterceptor() { super(); // <bean type="com.opensymphony.xwork2.UnknownHandler" name="convention" class="org.apache.struts2.convention.ConventionUnknownHandler"/> this.beans.add(new StrutsBean("com.opensymphony.xwork2.UnknownHandler", "convention", "org.apache.struts2.convention.ConventionUnknownHandler")); // <bean type="org.apache.struts2.convention.ActionConfigBuilder" name="convention" class="org.apache.struts2.convention.PackageBasedActionConfigBuilder"/> // <bean type="org.apache.struts2.convention.ActionNameBuilder" name="convention" class="org.apache.struts2.convention.SEOActionNameBuilder"/> // <bean type="org.apache.struts2.convention.ResultMapBuilder" name="convention" class="org.apache.struts2.convention.DefaultResultMapBuilder"/> // <bean type="org.apache.struts2.convention.InterceptorMapBuilder" name="convention" class="org.apache.struts2.convention.DefaultInterceptorMapBuilder"/> // <bean type="org.apache.struts2.convention.ConventionsService" name="convention" class="org.apache.struts2.convention.ConventionsServiceImpl"/> this.beans.add(new StrutsBean("org.apache.struts2.convention.ActionConfigBuilder", "convention", "org.apache.struts2.convention.PackageBasedActionConfigBuilder")); this.beans.add(new StrutsBean("org.apache.struts2.convention.ActionNameBuilder", "convention", "org.apache.struts2.convention.SEOActionNameBuilder")); this.beans.add(new StrutsBean("org.apache.struts2.convention.ResultMapBuilder", "convention", "org.apache.struts2.convention.DefaultResultMapBuilder")); this.beans.add(new StrutsBean("org.apache.struts2.convention.InterceptorMapBuilder", "convention", "org.apache.struts2.convention.DefaultInterceptorMapBuilder")); this.beans.add(new StrutsBean("org.apache.struts2.convention.ConventionsService", "convention", "org.apache.struts2.convention.ConventionsServiceImpl")); // <bean type="com.opensymphony.xwork2.config.PackageProvider" name="convention.packageProvider" class="org.apache.struts2.convention.ClasspathPackageProvider"/> // <bean type="com.opensymphony.xwork2.config.PackageProvider" name="convention.containerProvider" class="org.apache.struts2.convention.ClasspathConfigurationProvider"/> // this.beans.add(new StrutsBean("com.opensymphony.xwork2.config.PackageProvider", "convention.packageProvider", "org.apache.struts2.convention.ClasspathPackageProvider")); this.beans.add(new StrutsBean("com.opensymphony.xwork2.config.PackageProvider", "convention.packageProvider", "org.apache.struts2.convention.ClasspathConfigurationProvider")); // <constant name="struts.convention.actionConfigBuilder" value="convention"/> // <constant name="struts.convention.actionNameBuilder" value="convention"/> // <constant name="struts.convention.resultMapBuilder" value="convention"/> // <constant name="struts.convention.interceptorMapBuilder" value="convention"/> // <constant name="struts.convention.conventionsService" value="convention"/> this.constants.add(new StrutsConstant("struts.convention.actionConfigBuilder", "convention")); this.constants.add(new StrutsConstant("struts.convention.actionNameBuilder", "convention")); this.constants.add(new StrutsConstant("struts.convention.resultMapBuilder", "convention")); this.constants.add(new StrutsConstant("struts.convention.interceptorMapBuilder", "convention")); this.constants.add(new StrutsConstant("struts.convention.conventionsService", "convention")); // <constant name="struts.convention.result.path" value="/WEB-INF/content/"/> // <constant name="struts.convention.result.flatLayout" value="true"/> // <constant name="struts.convention.action.suffix" value="Action"/> // <constant name="struts.convention.action.disableScanning" value="false"/> // <constant name="struts.convention.action.mapAllMatches" value="false"/> // <constant name="struts.convention.action.checkImplementsAction" value="true"/> // <constant name="struts.convention.default.parent.package" value="convention-default"/> // <constant name="struts.convention.action.name.lowercase" value="true"/> // <constant name="struts.convention.action.name.separator" value="-"/> // <constant name="struts.convention.package.locators" value="action,actions,struts,struts2"/> // <constant name="struts.convention.package.locators.disable" value="false"/> // <constant name="struts.convention.package.locators.basePackage" value=""/> // <constant name="struts.convention.exclude.packages" value="org.apache.struts.*,org.apache.struts2.*,org.springframework.web.struts.*,org.springframework.web.struts2.*,org.hibernate.*"/> // <constant name="struts.convention.relative.result.types" value="dispatcher,velocity,freemarker"/> // <constant name="struts.convention.redirect.to.slash" value="true"/> // <constant name="struts.convention.action.alwaysMapExecute" value="true"/> // <constant name="struts.mapper.alwaysSelectFullNamespace" value="true"/> // <!-- <constant name="struts.convention.action.includeJars" /> --> // <constant name="struts.convention.action.fileProtocols" value="jar" /> this.constants.add(new StrutsConstant("struts.convention.result.path", "/WEB-INF/content/")); this.constants.add(new StrutsConstant("struts.convention.result.flatLayout", "true")); this.constants.add(new StrutsConstant("struts.convention.action.suffix", "Action")); this.constants.add(new StrutsConstant("struts.convention.action.disableScanning", "false")); this.constants.add(new StrutsConstant("struts.convention.action.mapAllMatches", "false")); this.constants.add(new StrutsConstant("struts.convention.action.checkImplementsAction", "true")); this.constants.add(new StrutsConstant("struts.convention.default.parent.package", "convention-default")); this.constants.add(new StrutsConstant("struts.convention.action.name.lowercase", "true")); this.constants.add(new StrutsConstant("struts.convention.action.name.separator", "-")); this.constants.add(new StrutsConstant("struts.convention.package.locators", "action,actions,struts,struts2")); this.constants.add(new StrutsConstant("struts.convention.package.locators.disable", "false")); this.constants.add(new StrutsConstant("struts.convention.package.locators.basePackage", "")); this.constants.add(new StrutsConstant("struts.convention.exclude.packages", "org.apache.struts.*,org.apache.struts2.*,org.springframework.web.struts.*,org.springframework.web.struts2.*,org.hibernate.*")); this.constants.add(new StrutsConstant("struts.convention.relative.result.types", "dispatcher,velocity,freemarker")); this.constants.add(new StrutsConstant("struts.convention.redirect.to.slash", "true")); this.constants.add(new StrutsConstant("struts.convention.action.alwaysMapExecute", "true")); this.constants.add(new StrutsConstant("struts.mapper.alwaysSelectFullNamespace", "true")); this.constants.add(new StrutsConstant("struts.convention.action.fileProtocols", "jar")); // <constant name="struts.convention.classes.reload" value="false" /> this.constants.add(new StrutsConstant("struts.convention.classes.reload", "false")); // <constant name="struts.convention.exclude.parentClassLoader" value="true" /> this.constants.add(new StrutsConstant("struts.convention.exclude.parentClassLoader", "true")); } } ======================================= package com.kenmcwilliams.struts.config; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.Interceptor; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Optional; /** * One instance of an interceptor is created per struts-package * @author ken */ public class PackageConfigInterceptor implements Interceptor{ public final HashSet<StrutsConstant> constants = new HashSet(); public final List<StrutsBean> beans = new ArrayList(); public List<StrutsBean> findBean(String name, String type){ List<StrutsBean> found = new ArrayList(); for(StrutsBean bean : beans){ if(bean.getName().equals(name) && bean.getType().equals(type)){ found.add(bean); } } return found; } public Optional<StrutsConstant> findConstant(String name){ Iterator<StrutsConstant> iterator = this.constants.iterator(); while(iterator.hasNext()){ StrutsConstant constant = iterator.next(); if(constant.getName().equals(name)){ return Optional.of(constant); } } return Optional.ofNullable(null); } @Override public void destroy() { } @Override public void init() { } @Override public String intercept(ActionInvocation invocation) throws Exception { return invocation.invoke(); } } ======================================= The above was just a quick hack for illustration. If struts could extend it's configuration and xml to provide package level scope (struts packages) and object for such purposes, and some functionality to provide configuration lookup from the perspective of a particular package a less hackish/reflective hoop-jumping could be done when reimplementing the conventions plugin, as it stands it's probably possible using this interceptor technique. On Fri, Jun 23, 2017 at 12:39 AM, Lukasz Lenart <lukaszlen...@apache.org> wrote: > 2017-06-22 2:45 GMT+02:00 Ken McWilliams <ken.mcwilli...@gmail.com>: > > Sure, doing Struts2/Shiro integration at the moment. Will come back to > > this, it was a rant from running into issues when setting up some > personal > > demo projects. The limitation from one static configuration to cover all > > conventions (which really just lets you use one convention, at least > well). > > Did I get this right, you want to have multiple configuration in the > same app, like having multiple struts.xml files in one app, right? > Hmm... maybe it is doable ... per a root package .... > > > Regards > -- > Ćukasz > + 48 606 323 122 http://www.lenart.org.pl/ > > --------------------------------------------------------------------- > To unsubscribe, e-mail: user-unsubscr...@struts.apache.org > For additional commands, e-mail: user-h...@struts.apache.org > > -- Sent from my C64 using a 300 baud modem