You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@struts.apache.org by "Ken McWilliams (JIRA)" <ji...@apache.org> on 2013/04/30 09:20:16 UTC

[jira] [Comment Edited] (WW-3937) The annotation @Result can have an extra attribute to hold tiles attributes

    [ https://issues.apache.org/jira/browse/WW-3937?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13645338#comment-13645338 ] 

Ken McWilliams edited comment on WW-3937 at 4/30/13 7:19 AM:
-------------------------------------------------------------

Here is a working demo of dynamically creating a tiles result. Only partial annotation based configuration is possible:

{code:title="TestTilesDynamicDefinitionResult.java"|borderStyle=solid}
package com.kenmcwilliams.employmentsystem.action.test;

import com.opensymphony.xwork2.ActionSupport;
import java.util.HashMap;
import java.util.Map;
import org.apache.struts2.convention.annotation.Result;
import org.apache.tiles.Attribute;

@Result(type = "tiles-definition", location = "dynamic-tiles-definition",
params = {
    "template", "/WEB-INF/test/test-template.jsp",
    "attributes", "attrs" //the value of "attributes" (which is "attrs") is evaluated using the value stack in the request
})
public class TestTilesDynamicDefinitionResult extends ActionSupport {

    private Map<String, Attribute> attrs = new HashMap();

    @Override
    public String execute(){
        attrs.put("body", new Attribute("/WEB-INF/test/test-dynamic-definition.jsp"));
        return SUCCESS;
    }
    
    public Map<String, Attribute> getAttrs() {
        return attrs;
    }

    public void setAttrs(Map<String, Attribute> attrs) {
        this.attrs = attrs;
    }
}
{code} 


{code:title="TilesDefinitionResult.java"|borderStyle=solid}
package com.kenmcwilliams.tiles.result;

import com.opensymphony.xwork2.ActionInvocation;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.dispatcher.ServletDispatcherResult;
import org.apache.tiles.Attribute;
import org.apache.tiles.Definition;
import org.apache.tiles.TilesContainer;
import org.apache.tiles.access.TilesAccess;
import org.apache.tiles.mgmt.MutableTilesContainer;
import org.apache.tiles.request.ApplicationContext;
import org.apache.tiles.request.servlet.ServletRequest;
import org.apache.tiles.request.servlet.ServletUtil;

public class TilesDefinitionResult extends ServletDispatcherResult {

    private static final Logger log = Logger.getLogger(TilesResult.class.getName());
    private String template;
    private String name = "dynamic-tiles-definition"; //definition name
    private String extendz;
    private String preparer;
    private String attributes;
    private Map<String, Attribute> evaluatedAttributes;
    private String addMissing = "false";

    public TilesDefinitionResult() {
        super();
    }

    public TilesDefinitionResult(String location) {
        super(location);
    }

    //location in this case refers to a previous tiles definition
    @Override
    public void doExecute(String location, ActionInvocation invocation) throws Exception {
        //location = "test.definition"; //for test
        //setLocation(location);
        //if (location != null && location.length() > 0){
        //    this.template = location;
        //String conditionalParse = this.conditionalParse(attributes, invocation);
        evaluatedAttributes = (Map<String, Attribute>) invocation.getStack().findValue(attributes);
        
        log.log(Level.INFO, "TilesResult doExecute() location: {0}", location);
        log.log(Level.INFO, "evaluatedAttributes['body']:{0}", evaluatedAttributes.get("body"));
        
        
        ServletContext context = ServletActionContext.getServletContext();
        ApplicationContext applicationContext = ServletUtil.getApplicationContext(context);
        TilesContainer container = TilesAccess.getContainer(applicationContext);
        //must use a mutable container
        if (container instanceof MutableTilesContainer) {
        } else {
            throw new Exception("A Mutable Tiles Container is required");
        }

        MutableTilesContainer mc = (MutableTilesContainer) container;
        Definition def = new Definition();

        if (template != null && template.length() > 0) {
            def.setTemplateAttribute(Attribute.createTemplateAttribute(template));
        }
        if (name != null && name.length() > 0) {
            def.setName(name);
        }
        if (extendz != null && extendz.length() > 0) {
            def.setExtends(extendz);
        }
        if (preparer != null && preparer.length() > 0) {
            def.setPreparer(preparer);
        }

        if (evaluatedAttributes != null && evaluatedAttributes.size() > 0) {
            if (addMissing.equalsIgnoreCase("true")) {
                def.addMissing(evaluatedAttributes);
            } else {
                def.addAll(evaluatedAttributes);
            }
        }
        
        HttpServletRequest request = ServletActionContext.getRequest();
        HttpServletResponse response = ServletActionContext.getResponse();
        ServletRequest servletRequest = new ServletRequest(applicationContext, request, response);
        mc.register(def, servletRequest);
        
        container.render(name, servletRequest);
    }


    public String getTemplate() {
        return template;
    }

    public void setTemplate(String template) {
        this.template = template;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setExtends(String extendz) {
        this.extendz = extendz;
    }

    public String getExtends() {
        return extendz;
    }

    public String getPreparer() {
        return preparer;
    }

    public void setPreparer(String preparer) {
        this.preparer = preparer;
    }

    public String getAttributes() {
        return attributes;
    }

    public void setAttributes(String attributes) {
        this.attributes = attributes;
    }

    public String getAddMissing() {
        return addMissing;
    }

    public void setAddMissing(String addMissing) {
        this.addMissing = addMissing;
    }
}
{code}

Very basic testing has shown this to work but no serious testing was done. 
                
      was (Author: ken_mcwilliams):
    Here is a working demo of dynamically creating a tiles result. Only partial annotation based configuration is possible:

{code:title="TestTilesDynamicDefinitionResult.java"|borderStyle=solid}
package com.kenmcwilliams.employmentsystem.action.test;

import com.opensymphony.xwork2.ActionSupport;
import java.util.HashMap;
import java.util.Map;
import org.apache.struts2.convention.annotation.Result;
import org.apache.tiles.Attribute;

//Attributes can be list attributes and are nested or regular attributes
//Attributes have a number of paramers
//as such a string based only configuration would be terribly complex to use
//or only partially implemented
@Result(type = "tiles-definition", location = "dynamic-tiles-definition",
params = {
    "template", "/WEB-INF/test/test-template.jsp",
    "attributes", "attrs" //the value of "attributes" (which is "attrs") is evaluated using the value stack in the request
})
public class TestTilesDynamicDefinitionResult extends ActionSupport {

    private Map<String, Attribute> attrs = new HashMap();

    @Override
    public String execute(){
        attrs.put("body", new Attribute("/WEB-INF/test/test-dynamic-definition.jsp"));
        return SUCCESS;
    }
    
    public Map<String, Attribute> getAttrs() {
        return attrs;
    }

    public void setAttrs(Map<String, Attribute> attrs) {
        this.attrs = attrs;
    }
}
{code} 


{code:title="TilesDefinitionResult.java"|borderStyle=solid}
package com.kenmcwilliams.tiles.result;

import com.opensymphony.xwork2.ActionInvocation;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.dispatcher.ServletDispatcherResult;
import org.apache.tiles.Attribute;
import org.apache.tiles.Definition;
import org.apache.tiles.TilesContainer;
import org.apache.tiles.access.TilesAccess;
import org.apache.tiles.mgmt.MutableTilesContainer;
import org.apache.tiles.request.ApplicationContext;
import org.apache.tiles.request.servlet.ServletRequest;
import org.apache.tiles.request.servlet.ServletUtil;

public class TilesDefinitionResult extends ServletDispatcherResult {

    private static final Logger log = Logger.getLogger(TilesResult.class.getName());
    private String template;
    private String name = "dynamic-tiles-definition"; //definition name
    private String extendz;
    private String preparer;
    private String attributes;
    private Map<String, Attribute> evaluatedAttributes;
    private String addMissing = "false";

    public TilesDefinitionResult() {
        super();
    }

    public TilesDefinitionResult(String location) {
        super(location);
    }

    //location in this case refers to a previous tiles definition
    @Override
    public void doExecute(String location, ActionInvocation invocation) throws Exception {
        //location = "test.definition"; //for test
        //setLocation(location);
        //if (location != null && location.length() > 0){
        //    this.template = location;
        //String conditionalParse = this.conditionalParse(attributes, invocation);
        evaluatedAttributes = (Map<String, Attribute>) invocation.getStack().findValue(attributes);
        
        log.log(Level.INFO, "TilesResult doExecute() location: {0}", location);
        log.log(Level.INFO, "evaluatedAttributes['body']:{0}", evaluatedAttributes.get("body"));
        
        
        ServletContext context = ServletActionContext.getServletContext();
        ApplicationContext applicationContext = ServletUtil.getApplicationContext(context);
        TilesContainer container = TilesAccess.getContainer(applicationContext);
        //must use a mutable container
        if (container instanceof MutableTilesContainer) {
        } else {
            throw new Exception("A Mutable Tiles Container is required");
        }

        MutableTilesContainer mc = (MutableTilesContainer) container;
        Definition def = new Definition();

        if (template != null && template.length() > 0) {
            def.setTemplateAttribute(Attribute.createTemplateAttribute(template));
        }
        if (name != null && name.length() > 0) {
            def.setName(name);
        }
        if (extendz != null && extendz.length() > 0) {
            def.setExtends(extendz);
        }
        if (preparer != null && preparer.length() > 0) {
            def.setPreparer(preparer);
        }

        if (evaluatedAttributes != null && evaluatedAttributes.size() > 0) {
            if (addMissing.equalsIgnoreCase("true")) {
                def.addMissing(evaluatedAttributes);
            } else {
                def.addAll(evaluatedAttributes);
            }
        }
        
        HttpServletRequest request = ServletActionContext.getRequest();
        HttpServletResponse response = ServletActionContext.getResponse();
        ServletRequest servletRequest = new ServletRequest(applicationContext, request, response);
        mc.register(def, servletRequest);
        
        container.render(name, servletRequest);
    }


    public String getTemplate() {
        return template;
    }

    public void setTemplate(String template) {
        this.template = template;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setExtends(String extendz) {
        this.extendz = extendz;
    }

    public String getExtends() {
        return extendz;
    }

    public String getPreparer() {
        return preparer;
    }

    public void setPreparer(String preparer) {
        this.preparer = preparer;
    }

    public String getAttributes() {
        return attributes;
    }

    public void setAttributes(String attributes) {
        this.attributes = attributes;
    }

    public String getAddMissing() {
        return addMissing;
    }

    public void setAddMissing(String addMissing) {
        this.addMissing = addMissing;
    }
}
{code}

Very basic testing has shown this to work but no serious testing was done. 
                  
> The annotation @Result can have an extra attribute to hold tiles attributes
> ---------------------------------------------------------------------------
>
>                 Key: WW-3937
>                 URL: https://issues.apache.org/jira/browse/WW-3937
>             Project: Struts 2
>          Issue Type: Improvement
>          Components: Plugin - Tiles
>    Affects Versions: 2.3.7
>            Reporter: Daniel Woo
>            Priority: Minor
>             Fix For: 2.3.15
>
>
> Currently the @Result annotation for tiles can only specify a location to render, e.g.
> {code:java}
> @Action(value = "/home", results = {@Result(name = "success", location = "home", type = "tiles")})
> {code}
> What I want is to add a new attribute like this:
> {code:java}
> @Action(value = "/home", results = {@Result(name = "success", location = "home", tilesAttr={"loadcss", "/css/home.css"}, type = "tiles")})
> {code}
> The reason is to utilize wildcard tiles definition. Suppose we have the wildcard tiles definition below,
> {code:xml}
> <definition name="*.*.*" extends="{3}-layout">
>     <put-attribute name="body" value="/view/{1}/{2}.jsp"/>
>     <put-attribute name="loadcss" value=""/>
> </definition>
> {code}
> The tiles attribute 'loadcss' should be set dynamically, or specified in the annotation. Currently since the tiles plugin does not support the attribute yet, we have to do that in the tiles configuration file with <put-attribute>, that means we have to explicitly define each tiles definition without wildcard support.

--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see: http://www.atlassian.com/software/jira