struts-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Ken McWilliams <ken.mcwilli...@gmail.com>
Subject Re: Limitations using Struts2-conventions-plugin (lack of multiple configuration roots)
Date Fri, 23 Jun 2017 21:22:02 GMT
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 <lukaszlenart@apache.org>
wrote:

> 2017-06-22 2:45 GMT+02:00 Ken McWilliams <ken.mcwilliams@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-unsubscribe@struts.apache.org
> For additional commands, e-mail: user-help@struts.apache.org
>
>


-- 
Sent from my C64 using a 300 baud modem

Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message