Author: jeromy Date: Sun Apr 13 19:57:22 2008 New Revision: 647650 URL: http://svn.apache.org/viewvc?rev=647650&view=rev Log: The closing I18n tag now throws an exception if it popped an unexpected object from the stack.
WW-2539 Modified: struts/struts2/trunk/core/src/main/java/org/apache/struts2/components/I18n.java struts/struts2/trunk/core/src/test/java/org/apache/struts2/views/jsp/I18nTagTest.java Modified: struts/struts2/trunk/core/src/main/java/org/apache/struts2/components/I18n.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/components/I18n.java?rev=647650&r1=647649&r2=647650&view=diff ============================================================================== --- struts/struts2/trunk/core/src/main/java/org/apache/struts2/components/I18n.java (original) +++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/components/I18n.java Sun Apr 13 19:57:22 2008 @@ -31,10 +31,13 @@ import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.LocaleProvider; import com.opensymphony.xwork2.TextProviderFactory; +import com.opensymphony.xwork2.TextProvider; import com.opensymphony.xwork2.inject.Container; import com.opensymphony.xwork2.inject.Inject; import com.opensymphony.xwork2.util.LocalizedTextUtil; import com.opensymphony.xwork2.util.ValueStack; +import com.opensymphony.xwork2.util.logging.Logger; +import com.opensymphony.xwork2.util.logging.LoggerFactory; /** * <!-- START SNIPPET: javadoc --> @@ -84,9 +87,13 @@ @StrutsTag(name="i18n", tldTagClass="org.apache.struts2.views.jsp.I18nTag", description="Get a resource bundle" + " and place it on the value stack") public class I18n extends Component { + + private static final Logger LOG = LoggerFactory.getLogger(I18n.class); + protected boolean pushed; protected String name; protected Container container; + private TextProvider textProvider; public I18n(ValueStack stack) { super(stack); @@ -112,11 +119,12 @@ final Locale locale = (Locale) getStack().getContext().get(ActionContext.LOCALE); TextProviderFactory tpf = new TextProviderFactory(); container.inject(tpf); - getStack().push(tpf.createInstance(bundle, new LocaleProvider() { - public Locale getLocale() { - return locale; - } - })); + textProvider = tpf.createInstance(bundle, new LocaleProvider() { + public Locale getLocale() { + return locale; + } + }); + getStack().push(textProvider); pushed = true; } } catch (Exception e) { @@ -127,9 +135,15 @@ return result; } - public boolean end(Writer writer, String body) { + public boolean end(Writer writer, String body) throws StrutsException { if (pushed) { - getStack().pop(); + Object o = getStack().pop(); + if ((o == null) || (!o.equals(textProvider))) { + LOG.error("A closing i18n tag attempted to pop its own TextProvider from the top of the ValueStack but popped an unexpected object ("+(o != null ? o.getClass() : "null")+"). " + + "Refactor the page within the i18n tags to ensure no objects are pushed onto the ValueStack without popping them prior to the closing tag. " + + "If you see this message it's likely that the i18n's TextProvider is still on the stack and will continue to provide message resources after the closing tag."); + throw new StrutsException("A closing i18n tag attempted to pop its TextProvider from the top of the ValueStack but popped an unexpected object ("+(o != null ? o.getClass() : "null")+")"); + } } return super.end(writer, body); Modified: struts/struts2/trunk/core/src/test/java/org/apache/struts2/views/jsp/I18nTagTest.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/test/java/org/apache/struts2/views/jsp/I18nTagTest.java?rev=647650&r1=647649&r2=647650&view=diff ============================================================================== --- struts/struts2/trunk/core/src/test/java/org/apache/struts2/views/jsp/I18nTagTest.java (original) +++ struts/struts2/trunk/core/src/test/java/org/apache/struts2/views/jsp/I18nTagTest.java Sun Apr 13 19:57:22 2008 @@ -3,6 +3,7 @@ import org.apache.struts2.TestAction; import org.apache.struts2.StrutsTestCase; import org.apache.struts2.ServletActionContext; +import org.apache.struts2.StrutsException; import com.mockobjects.servlet.MockPageContext; import com.mockobjects.servlet.MockJspWriter; import com.opensymphony.xwork2.util.ValueStack; @@ -59,5 +60,41 @@ e.printStackTrace(); fail(); } + } + + /** + * Asserts that an exception is thrown when something unexpected is popped off the stack by the closing tag + * + * @throws Exception + */ + public void testUnexpectedPop() throws Exception { + + // set the resource bundle + tag.setName("testmessages"); + + int result = 0; + + try { + result = tag.doStartTag(); + } catch (JspException e) { + e.printStackTrace(); + fail(); + } + + stack.push("An new object on top of the stack"); + + assertEquals(TagSupport.EVAL_BODY_INCLUDE, result); + + try { + result = tag.doEndTag(); + fail(); + } catch (JspException e) { + e.printStackTrace(); + fail(); + } catch (StrutsException e) { + e.printStackTrace(); + // pass + } + } }