Author: lukaszlenart Date: Fri Apr 6 08:17:00 2012 New Revision: 1310221 URL: http://svn.apache.org/viewvc?rev=1310221&view=rev Log: WW-3174 adds logic to support dynamic attributes in tags used with FreeMarker templates
Added: struts/struts2/trunk/core/src/test/resources/org/apache/struts2/views/freemarker/dynaAttributes.ftl - copied, changed from r1310204, struts/struts2/trunk/core/src/test/resources/org/apache/struts2/views/freemarker/callActionFreeMarker.ftl Modified: struts/struts2/trunk/core/src/main/java/org/apache/struts2/components/UIBean.java struts/struts2/trunk/core/src/test/java/org/apache/struts2/views/freemarker/FreeMarkerResultTest.java struts/struts2/trunk/core/src/test/resources/struts.xml Modified: struts/struts2/trunk/core/src/main/java/org/apache/struts2/components/UIBean.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/components/UIBean.java?rev=1310221&r1=1310220&r2=1310221&view=diff ============================================================================== --- struts/struts2/trunk/core/src/main/java/org/apache/struts2/components/UIBean.java (original) +++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/components/UIBean.java Fri Apr 6 08:17:00 2012 @@ -21,31 +21,34 @@ package org.apache.struts2.components; -import java.io.Writer; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - +import com.opensymphony.xwork2.config.ConfigurationException; +import com.opensymphony.xwork2.inject.Inject; +import com.opensymphony.xwork2.util.ValueStack; +import com.opensymphony.xwork2.util.logging.Logger; +import com.opensymphony.xwork2.util.logging.LoggerFactory; import org.apache.struts2.StrutsConstants; import org.apache.struts2.StrutsException; -import org.apache.struts2.util.TextProviderHelper; import org.apache.struts2.components.template.Template; import org.apache.struts2.components.template.TemplateEngine; import org.apache.struts2.components.template.TemplateEngineManager; import org.apache.struts2.components.template.TemplateRenderingContext; +import org.apache.struts2.util.TextProviderHelper; import org.apache.struts2.views.annotations.StrutsTagAttribute; import org.apache.struts2.views.util.ContextUtil; -import com.opensymphony.xwork2.config.ConfigurationException; -import com.opensymphony.xwork2.inject.Inject; -import com.opensymphony.xwork2.util.ValueStack; -import com.opensymphony.xwork2.util.logging.Logger; -import com.opensymphony.xwork2.util.logging.LoggerFactory; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.Writer; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; /** * UIBean is the standard superclass of all Struts UI componentns. @@ -491,6 +494,9 @@ public abstract class UIBean extends Com protected String defaultUITheme; protected TemplateEngineManager templateEngineManager; + // dynamic attributes support for tags used with FreeMarker templates + protected static Map<Class, Set<String>> standardAttributesMap = new ConcurrentHashMap<Class, Set<String>>(); + @Inject(StrutsConstants.STRUTS_UI_TEMPLATEDIR) public void setDefaultTemplateDir(String dir) { this.defaultTemplateDir = dir; @@ -1195,7 +1201,48 @@ public abstract class UIBean extends Com this.tooltipIconPath = tooltipIconPath; } - public void setDynamicAttributes(Map<String,Object> dynamicAttributes) { - this.dynamicAttributes = dynamicAttributes; - } + public void setDynamicAttributes(Map<String, Object> dynamicAttributes) { + this.dynamicAttributes.putAll(dynamicAttributes); } + + @Override + /** + * supports dynamic attributes for freemarker ui tags + * @see https://issues.apache.org/jira/browse/WW-3174 + */ + public void copyParams(Map params) { + super.copyParams(params); + Set<String> standardAttributes = getStandardAttributes(); + for (Object o : params.entrySet()) { + Map.Entry entry = (Map.Entry) o; + String key = (String) entry.getKey(); + if (!key.equals("dynamicAttributes") && !standardAttributes.contains(key)){ + dynamicAttributes.put(key, entry.getValue()); + } + } + } + + protected Set<String> getStandardAttributes() { + Class clz = getClass(); + Set<String> standardAttributes = standardAttributesMap.get(clz); + if (standardAttributes == null) { + standardAttributes = new HashSet<String>(); + standardAttributesMap.put(clz, standardAttributes); + while (clz != null) { + for (Field f : clz.getDeclaredFields()) { + if (Modifier.isProtected(f.getModifiers()) + && (f.getType().equals(String.class) || clz.equals(ListUIBean.class) + && f.getName().equals("list"))) + standardAttributes.add(f.getName()); + } + if (clz.equals(UIBean.class)) { + break; + } else { + clz = clz.getSuperclass(); + } + } + } + return standardAttributes; + } + +} \ No newline at end of file Modified: struts/struts2/trunk/core/src/test/java/org/apache/struts2/views/freemarker/FreeMarkerResultTest.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/test/java/org/apache/struts2/views/freemarker/FreeMarkerResultTest.java?rev=1310221&r1=1310220&r2=1310221&view=diff ============================================================================== --- struts/struts2/trunk/core/src/test/java/org/apache/struts2/views/freemarker/FreeMarkerResultTest.java (original) +++ struts/struts2/trunk/core/src/test/java/org/apache/struts2/views/freemarker/FreeMarkerResultTest.java Fri Apr 6 08:17:00 2012 @@ -21,12 +21,12 @@ package org.apache.struts2.views.freemarker; -import java.io.File; -import java.io.PrintWriter; -import java.io.StringWriter; - -import junit.framework.TestCase; - +import com.opensymphony.xwork2.ActionContext; +import com.opensymphony.xwork2.mock.MockActionInvocation; +import com.opensymphony.xwork2.util.ClassLoaderUtil; +import com.opensymphony.xwork2.util.ValueStack; +import freemarker.template.Configuration; +import freemarker.template.TemplateExceptionHandler; import org.apache.struts2.ServletActionContext; import org.apache.struts2.StrutsStatics; import org.apache.struts2.StrutsTestCase; @@ -35,20 +35,13 @@ import org.apache.struts2.dispatcher.map import org.apache.struts2.dispatcher.mapper.ActionMapping; import org.apache.struts2.views.jsp.StrutsMockHttpServletResponse; import org.apache.struts2.views.jsp.StrutsMockServletContext; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.mock.web.MockServletContext; -import org.springframework.core.io.DefaultResourceLoader; import org.easymock.EasyMock; - -import com.opensymphony.xwork2.ActionContext; -import com.opensymphony.xwork2.mock.MockActionInvocation; -import com.opensymphony.xwork2.util.ValueStack; -import com.opensymphony.xwork2.util.ValueStackFactory; +import org.springframework.mock.web.MockHttpServletRequest; import javax.servlet.ServletContext; - -import freemarker.template.TemplateExceptionHandler; -import freemarker.template.Configuration; +import java.io.File; +import java.io.PrintWriter; +import java.io.StringWriter; /** * Test case for FreeMarkerResult. @@ -184,6 +177,46 @@ public class FreeMarkerResultTest extend assertEquals("text/xml", response.getContentType()); } + public void testDynamicAttributesSupport() throws Exception { + //get fm config to use it in mock servlet context + FreemarkerManager freemarkerManager = container.getInstance(FreemarkerManager.class); + Configuration freemarkerConfig = freemarkerManager.getConfiguration(ServletActionContext.getServletContext()); + freemarkerConfig.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); + + ServletContext servletContext = EasyMock.createNiceMock(ServletContext.class); + + File file = new File(FreeMarkerResultTest.class.getResource("dynaAttributes.ftl").toURI()); + EasyMock.expect(servletContext.getRealPath("/tutorial/org/apache/struts2/views/freemarker/dynaAttributes.ftl")).andReturn(file.getAbsolutePath()); + + file = new File(ClassLoaderUtil.getResource("template/simple/text.ftl", getClass()).toURI()); + EasyMock.expect(servletContext.getRealPath("/template/simple/text.ftl")).andReturn(file.getAbsolutePath()); + + file = new File(ClassLoaderUtil.getResource("template/simple/css.ftl", getClass()).toURI()); + EasyMock.expect(servletContext.getRealPath("/template/simple/css.ftl")).andReturn(file.getAbsolutePath()); + + file = new File(ClassLoaderUtil.getResource("template/simple/scripting-events.ftl", getClass()).toURI()); + EasyMock.expect(servletContext.getRealPath("/template/simple/scripting-events.ftl")).andReturn(file.getAbsolutePath()); + + file = new File(ClassLoaderUtil.getResource("template/simple/common-attributes.ftl", getClass()).toURI()); + EasyMock.expect(servletContext.getRealPath("/template/simple/common-attributes.ftl")).andReturn(file.getAbsolutePath()); + + file = new File(ClassLoaderUtil.getResource("template/simple/dynamic-attributes.ftl", getClass()).toURI()); + EasyMock.expect(servletContext.getRealPath("/template/simple/dynamic-attributes.ftl")).andReturn(file.getAbsolutePath()); + + EasyMock.expect(servletContext.getAttribute(FreemarkerManager.CONFIG_SERVLET_CONTEXT_KEY)).andReturn(freemarkerConfig).anyTimes(); + EasyMock.replay(servletContext); + + freemarkerConfig.setServletContextForTemplateLoading(servletContext, null); + ServletActionContext.setServletContext(servletContext); + + + request.setRequestURI("/tutorial/test6.action"); + Dispatcher dispatcher = Dispatcher.getInstance(); + ActionMapping mapping = dispatcher.getContainer().getInstance(ActionMapper.class).getMapping(request, dispatcher.getConfigurationManager()); + dispatcher.serviceAction(request, response, servletContext, mapping); + assertEquals("<input type=\"text\" name=\"test\" value=\"\" id=\"test\" placeholder=\"input\" foo=\"bar\"/>", stringWriter.toString()); + } + protected void setUp() throws Exception { super.setUp(); mgr = new FreemarkerManager(); Copied: struts/struts2/trunk/core/src/test/resources/org/apache/struts2/views/freemarker/dynaAttributes.ftl (from r1310204, struts/struts2/trunk/core/src/test/resources/org/apache/struts2/views/freemarker/callActionFreeMarker.ftl) URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/test/resources/org/apache/struts2/views/freemarker/dynaAttributes.ftl?p2=struts/struts2/trunk/core/src/test/resources/org/apache/struts2/views/freemarker/dynaAttributes.ftl&p1=struts/struts2/trunk/core/src/test/resources/org/apache/struts2/views/freemarker/callActionFreeMarker.ftl&r1=1310204&r2=1310221&rev=1310221&view=diff ============================================================================== --- struts/struts2/trunk/core/src/test/resources/org/apache/struts2/views/freemarker/callActionFreeMarker.ftl (original) +++ struts/struts2/trunk/core/src/test/resources/org/apache/struts2/views/freemarker/dynaAttributes.ftl Fri Apr 6 08:17:00 2012 @@ -20,4 +20,4 @@ * under the License. */ --> -before<@s.action namespace="/tutorial" name="test4" executeResult="true" rethrowException="true"/>after \ No newline at end of file +<@s.textfield name="test" dynamicAttributes={"placeholder":"input","foo":"bar"}/> \ No newline at end of file Modified: struts/struts2/trunk/core/src/test/resources/struts.xml URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/test/resources/struts.xml?rev=1310221&r1=1310220&r2=1310221&view=diff ============================================================================== --- struts/struts2/trunk/core/src/test/resources/struts.xml (original) +++ struts/struts2/trunk/core/src/test/resources/struts.xml Fri Apr 6 08:17:00 2012 @@ -63,6 +63,12 @@ </result> </action> + <action name="test6" class="com.opensymphony.xwork2.ActionSupport"> + <result type="freemarker"> + <param name="location">org/apache/struts2/views/freemarker/dynaAttributes.ftl</param> + </result> + </action> + </package> <package name="sitegraph" namespace="/tutorial/sitegraph" extends="struts-default">