You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by lu...@apache.org on 2011/12/28 22:47:20 UTC

svn commit: r1225353 - in /struts/struts2/trunk/core/src: main/java/org/apache/struts2/components/ main/java/org/apache/struts2/views/jsp/ site/resources/tags/ test/java/org/apache/struts2/ test/java/org/apache/struts2/views/jsp/

Author: lukaszlenart
Date: Wed Dec 28 21:47:20 2011
New Revision: 1225353

URL: http://svn.apache.org/viewvc?rev=1225353&view=rev
Log:
WW-3284 - adds new Number tag

Added:
    struts/struts2/trunk/core/src/main/java/org/apache/struts2/components/Number.java
    struts/struts2/trunk/core/src/main/java/org/apache/struts2/views/jsp/NumberTag.java
    struts/struts2/trunk/core/src/site/resources/tags/number.html
    struts/struts2/trunk/core/src/test/java/org/apache/struts2/views/jsp/NumberTagTest.java
Modified:
    struts/struts2/trunk/core/src/test/java/org/apache/struts2/TestAction.java

Added: struts/struts2/trunk/core/src/main/java/org/apache/struts2/components/Number.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/components/Number.java?rev=1225353&view=auto
==============================================================================
--- struts/struts2/trunk/core/src/main/java/org/apache/struts2/components/Number.java (added)
+++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/components/Number.java Wed Dec 28 21:47:20 2011
@@ -0,0 +1,404 @@
+/**
+ *
+ */
+package org.apache.struts2.components;
+
+/*
+ * $Id$
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.util.ValueStack;
+import com.opensymphony.xwork2.util.logging.Logger;
+import com.opensymphony.xwork2.util.logging.LoggerFactory;
+import org.apache.struts2.views.annotations.StrutsTag;
+import org.apache.struts2.views.annotations.StrutsTagAttribute;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.math.RoundingMode;
+import java.text.NumberFormat;
+import java.util.Currency;
+
+/**
+ * <!-- START SNIPPET: javadoc -->
+ * <p/>
+ * Format Number object in different ways.
+ * <p>
+ * The number tag will allow you to format a Number in a quick and easy way,
+ * based on the java.text.NumberFormat class. There are four basic number types,
+ * a number, a currency, a percentage and an integer. If a currency is
+ * specified, the number format will match the given currency. Further
+ * parameters can be overridden as needed.
+ * <p/>
+ * If a type is not defined, it will finally fall back to the default
+ * NumberFormat.getNumberInstance() formatting.
+ * <p/>
+ * <b>Note</b>: If the requested Number object isn't found on the stack, a blank
+ * will be returned.
+ * </p>
+ * <p/>
+ * Configurable attributes are :-
+ * <ul>
+ * <li>name</li>
+ * <li>currency - you can specify your own currency or as an OGNL expression</li>
+ * <li>type - if not specified try to find base on struts.number.format property</li>
+ * <li>groupingUsed - see NumberFormat.isGroupingUsed</li>
+ * <li>maximumFractionDigits - see NumberFormat.setMaximumFractionDigits</li>
+ * <li>maximumIntegerDigits - see NumberFormat.setMaximumIntegerDigits</li>
+ * <li>minimumFractionDigits - see NumberFormat.setMinimumFractionDigits</li>
+ * <li>minimumIntegerDigits - see NumberFormat.setMinimumIntegerDigits</li>
+ * <li>parseIntegerOnly - see NumberFormat.isParseIntegerOnly</li>
+ * <li>roundingMode - see below</li>
+ * </ul>
+ * <p/>
+ * <p/>
+ * <p/>
+ * Possible values for rounding mode are :-
+ * <ul>
+ * <li>ceiling</li>
+ * <li>down</li>
+ * <li>floor</li>
+ * <li>half-down</li>
+ * <li>half-even</li>
+ * <li>half-up</li>
+ * <li>unnecessary</li>
+ * <li>up</li>
+ * </ul>
+ * <p/>
+ * <p/>
+ * <p/>
+ * <!-- END SNIPPET: javadoc -->
+ * <p/>
+ * <p/>
+ * <b>Examples</b>
+ * <p/>
+ * <pre>
+ *  &lt;!-- START SNIPPET: example --&gt;
+ *  &lt;s:number name=&quot;invoice.total&quot; type=&quot;currency&quot; currency=&quot;XYZ&quot; /&gt;
+ *  &lt;s:number name=&quot;invoice.quantity&quot; type=&quot;number&quot; /&gt;
+ *  &lt;s:number name=&quot;invoice.discount&quot; type=&quot;percentage&quot; /&gt;
+ *  &lt;s:number name=&quot;invoice.terms&quot; type=&quot;integer&quot; /&gt;
+ *  &lt;!-- END SNIPPET: example --&gt;
+ * </pre>
+ * <p/>
+ * <code>Number</code>
+ */
+@StrutsTag(name = "number", tldBodyContent = "empty", tldTagClass = "org.apache.struts2.views.jsp.NumberTag", description = "Render a formatted number.")
+public class Number extends ContextBean {
+
+    private static final Logger LOG = LoggerFactory.getLogger(Number.class);
+    /**
+     * Property name to fall back when no format is specified
+     */
+    public static final String NUMBERTAG_PROPERTY = "struts.number.format";
+
+    private String name;
+
+    private String currency;
+
+    private String type;
+
+    private Boolean groupingUsed;
+
+    private Integer maximumFractionDigits;
+
+    private Integer maximumIntegerDigits;
+
+    private Integer minimumFractionDigits;
+
+    private Integer minimumIntegerDigits;
+
+    private Boolean parseIntegerOnly;
+
+    private String roundingMode;
+
+    public Number(ValueStack stack) {
+        super(stack);
+    }
+
+    public boolean end(Writer writer, String body) {
+        java.lang.Number number = findNumberName();
+
+        if (number != null) {
+
+            NumberFormat format = getNumberFormat();
+            findCurrency(format);
+            setNumberFormatParameters(format);
+            setRoundingMode(format);
+
+            String msg = format.format(number);
+            if (msg != null) {
+                try {
+                    if (getVar() == null) {
+                        writer.write(msg);
+                    } else {
+                        putInContext(msg);
+                    }
+                } catch (IOException e) {
+                    LOG.error("Could not write out Number tag", e);
+                }
+            }
+        }
+        return super.end(writer, "");
+    }
+
+    // try to find the currency, percentage and integer on the stack
+    private void findCurrency(NumberFormat format) {
+        if (currency != null) {
+            Object currencyValue = findValue(currency);
+            if (currencyValue != null) {
+                currency = currencyValue.toString();
+            }
+            try {
+                format.setCurrency(Currency.getInstance(currency));
+            } catch (IllegalArgumentException iae) {
+                LOG.error("Could not recognise a currency of [" + currency + "]");
+            }
+        }
+    }
+
+    private void setNumberFormatParameters(NumberFormat format) {
+        if (groupingUsed != null) {
+            format.setGroupingUsed(groupingUsed);
+        }
+        if (maximumFractionDigits != null) {
+            format.setMaximumFractionDigits(maximumFractionDigits);
+        }
+        if (maximumIntegerDigits != null) {
+            format.setMaximumIntegerDigits(maximumIntegerDigits);
+        }
+        if (minimumFractionDigits != null) {
+            format.setMinimumFractionDigits(minimumFractionDigits);
+        }
+        if (minimumIntegerDigits != null) {
+            format.setMinimumIntegerDigits(minimumIntegerDigits);
+        }
+        if (parseIntegerOnly != null) {
+            format.setParseIntegerOnly(parseIntegerOnly);
+        }
+    }
+
+    private java.lang.Number findNumberName() {
+        java.lang.Number number = null;
+        // find the name on the valueStack
+        try {
+            // suport Calendar also
+            Object numberObject = findValue(name);
+            if (numberObject instanceof java.lang.Number) {
+                number = (java.lang.Number) numberObject;
+            }
+        } catch (Exception e) {
+            LOG.error("Could not convert object with key [" + name + "] to a java.lang.Number instance");
+        }
+        return number;
+    }
+
+    private void setRoundingMode(NumberFormat format) {
+        if (roundingMode != null) {
+            roundingMode = findString(roundingMode);
+            if ("ceiling".equals(roundingMode)) {
+                format.setRoundingMode(RoundingMode.CEILING);
+            } else if ("down".equals(roundingMode)) {
+                format.setRoundingMode(RoundingMode.DOWN);
+            } else if ("floor".equals(roundingMode)) {
+                format.setRoundingMode(RoundingMode.FLOOR);
+            } else if ("half-down".equals(roundingMode)) {
+                format.setRoundingMode(RoundingMode.HALF_DOWN);
+            } else if ("half-even".equals(roundingMode)) {
+                format.setRoundingMode(RoundingMode.HALF_EVEN);
+            } else if ("half-up".equals(roundingMode)) {
+                format.setRoundingMode(RoundingMode.HALF_UP);
+            } else if ("unnecessary".equals(roundingMode)) {
+                format.setRoundingMode(RoundingMode.UNNECESSARY);
+            } else if ("up".equals(roundingMode)) {
+                format.setRoundingMode(RoundingMode.UP);
+            } else {
+                LOG.error("Could not recognise a roundingMode of [" + roundingMode + "]");
+            }
+        }
+    }
+
+    private NumberFormat getNumberFormat() {
+        NumberFormat format = null;
+        if (type == null) {
+            try {
+                type = findString(NUMBERTAG_PROPERTY);
+            } catch (Exception e) {
+                LOG.error("Could not find [" + NUMBERTAG_PROPERTY + "] on the stack!", e);
+            }
+        }
+        if (type != null) {
+            type = findString(type);
+            if ("currency".equals(type)) {
+                format = NumberFormat.getCurrencyInstance(ActionContext.getContext().getLocale());
+            } else if ("integer".equals(type)) {
+                format = NumberFormat.getIntegerInstance(ActionContext.getContext().getLocale());
+            } else if ("number".equals(type)) {
+                format = NumberFormat.getNumberInstance(ActionContext.getContext().getLocale());
+            } else if ("percent".equals(type)) {
+                format = NumberFormat.getPercentInstance(ActionContext.getContext().getLocale());
+            }
+        }
+        if (format == null) {
+            format = NumberFormat.getInstance(ActionContext.getContext().getLocale());
+        }
+        return format;
+    }
+
+    @StrutsTagAttribute(description = "Type of number formatter (currency, integer, number or percent, default is number)", rtexprvalue = false)
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    @StrutsTagAttribute(description = "The currency to use for a currency format", type = "String", defaultValue = "")
+    public void setCurrency(String currency) {
+        this.currency = currency;
+    }
+
+    /**
+     * @return Returns the name.
+     */
+    public String getName() {
+        return name;
+    }
+
+    @StrutsTagAttribute(description = "The number value to format", required = true)
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * @return Returns the format.
+     */
+    public String getType() {
+        return type;
+    }
+
+    /**
+     * @return Returns the currency.
+     */
+    public String getCurrency() {
+        return currency;
+    }
+
+    @StrutsTagAttribute(description = "Whether grouping is used", type = "Boolean")
+    public void setGroupingUsed(Boolean groupingUsed) {
+        this.groupingUsed = groupingUsed;
+    }
+
+    /**
+     * @return Returns the grouping used.
+     */
+    public Boolean isGroupingUsed() {
+        return groupingUsed;
+    }
+
+    /**
+     * @return the maximumFractionDigits
+     */
+    public Integer getMaximumFractionDigits() {
+        return maximumFractionDigits;
+    }
+
+    /**
+     * @param maximumFractionDigits the maximumFractionDigits to set
+     */
+    @StrutsTagAttribute(description = "Maximum fraction digits", type = "Integer")
+    public void setMaximumFractionDigits(Integer maximumFractionDigits) {
+        this.maximumFractionDigits = maximumFractionDigits;
+    }
+
+    /**
+     * @return the maximumIntegerDigits
+     */
+    public Integer getMaximumIntegerDigits() {
+        return maximumIntegerDigits;
+    }
+
+    /**
+     * @param maximumIntegerDigits the maximumIntegerDigits to set
+     */
+    @StrutsTagAttribute(description = "Maximum integer digits", type = "Integer")
+    public void setMaximumIntegerDigits(Integer maximumIntegerDigits) {
+        this.maximumIntegerDigits = maximumIntegerDigits;
+    }
+
+    /**
+     * @return the minimumFractionDigits
+     */
+    public Integer getMinimumFractionDigits() {
+        return minimumFractionDigits;
+    }
+
+    /**
+     * @param minimumFractionDigits the minimumFractionDigits to set
+     */
+    @StrutsTagAttribute(description = "Minimum fraction digits", type = "Integer")
+    public void setMinimumFractionDigits(Integer minimumFractionDigits) {
+        this.minimumFractionDigits = minimumFractionDigits;
+    }
+
+    /**
+     * @return the minimumIntegerDigits
+     */
+    public Integer getMinimumIntegerDigits() {
+        return minimumIntegerDigits;
+    }
+
+    /**
+     * @param minimumIntegerDigits the minimumIntegerDigits to set
+     */
+    @StrutsTagAttribute(description = "Maximum integer digits", type = "Integer")
+    public void setMinimumIntegerDigits(Integer minimumIntegerDigits) {
+        this.minimumIntegerDigits = minimumIntegerDigits;
+    }
+
+    /**
+     * @return the parseIntegerOnly
+     */
+    public Boolean isParseIntegerOnly() {
+        return parseIntegerOnly;
+    }
+
+    /**
+     * @param parseIntegerOnly the parseIntegerOnly to set
+     */
+    @StrutsTagAttribute(description = "Parse integer only", type = "Boolean")
+    public void setParseIntegerOnly(Boolean parseIntegerOnly) {
+        this.parseIntegerOnly = parseIntegerOnly;
+    }
+
+    /**
+     * @return the roundingMode
+     */
+    public String getRoundingMode() {
+        return roundingMode;
+    }
+
+    /**
+     * @param roundingMode the roundingMode to set
+     */
+    @StrutsTagAttribute(description = "The rounding mode to use", type = "String")
+    public void setRoundingMode(String roundingMode) {
+        this.roundingMode = roundingMode;
+    }
+
+}

Added: struts/struts2/trunk/core/src/main/java/org/apache/struts2/views/jsp/NumberTag.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/views/jsp/NumberTag.java?rev=1225353&view=auto
==============================================================================
--- struts/struts2/trunk/core/src/main/java/org/apache/struts2/views/jsp/NumberTag.java (added)
+++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/views/jsp/NumberTag.java Wed Dec 28 21:47:20 2011
@@ -0,0 +1,139 @@
+package org.apache.struts2.views.jsp;
+
+/*
+ * $Id$
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import com.opensymphony.xwork2.util.ValueStack;
+import org.apache.struts2.components.Component;
+import org.apache.struts2.components.Number;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * @see Number
+ */
+public class NumberTag extends ContextBeanTag {
+
+    private static final long serialVersionUID = -6216963123295613440L;
+
+    private String name;
+    private String currency;
+    private String type;
+    private Boolean groupingUsed;
+    private Integer maximumFractionDigits;
+    private Integer maximumIntegerDigits;
+    private Integer minimumFractionDigits;
+    private Integer minimumIntegerDigits;
+    private Boolean parseIntegerOnly;
+    private String roundingMode;
+
+    public Component getBean(ValueStack stack, HttpServletRequest req, HttpServletResponse res) {
+        return new Number(stack);
+    }
+
+    protected void populateParams() {
+        super.populateParams();
+        Number n = (Number) component;
+        n.setName(name);
+        n.setCurrency(currency);
+        n.setType(type);
+        n.setGroupingUsed(groupingUsed);
+        n.setMaximumFractionDigits(maximumFractionDigits);
+        n.setMaximumIntegerDigits(maximumIntegerDigits);
+        n.setMinimumFractionDigits(minimumFractionDigits);
+        n.setMinimumIntegerDigits(minimumIntegerDigits);
+        n.setParseIntegerOnly(parseIntegerOnly);
+        n.setRoundingMode(roundingMode);
+
+    }
+
+    /**
+     * @param name the name to set
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * @param currency the currency to set
+     */
+    public void setCurrency(String currency) {
+        this.currency = currency;
+    }
+
+    /**
+     * @param type the type to set
+     */
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    /**
+     * @param groupingUsed the groupingUsed to set
+     */
+    public void setGroupingUsed(Boolean groupingUsed) {
+        this.groupingUsed = groupingUsed;
+    }
+
+    /**
+     * @param maximumFractionDigits the maximumFractionDigits to set
+     */
+    public void setMaximumFractionDigits(Integer maximumFractionDigits) {
+        this.maximumFractionDigits = maximumFractionDigits;
+    }
+
+    /**
+     * @param maximumIntegerDigits the maximumIntegerDigits to set
+     */
+    public void setMaximumIntegerDigits(Integer maximumIntegerDigits) {
+        this.maximumIntegerDigits = maximumIntegerDigits;
+    }
+
+    /**
+     * @param minimumFractionDigits the minimumFractionDigits to set
+     */
+    public void setMinimumFractionDigits(Integer minimumFractionDigits) {
+        this.minimumFractionDigits = minimumFractionDigits;
+    }
+
+    /**
+     * @param minimumIntegerDigits the minimumIntegerDigits to set
+     */
+    public void setMinimumIntegerDigits(Integer minimumIntegerDigits) {
+        this.minimumIntegerDigits = minimumIntegerDigits;
+    }
+
+    /**
+     * @param parseIntegerOnly the parseIntegerOnly to set
+     */
+    public void setParseIntegerOnly(Boolean parseIntegerOnly) {
+        this.parseIntegerOnly = parseIntegerOnly;
+    }
+
+    /**
+     * @param roundingMode the roundingMode to set
+     */
+    public void setRoundingMode(String roundingMode) {
+        this.roundingMode = roundingMode;
+    }
+
+}

Added: struts/struts2/trunk/core/src/site/resources/tags/number.html
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/site/resources/tags/number.html?rev=1225353&view=auto
==============================================================================
--- struts/struts2/trunk/core/src/site/resources/tags/number.html (added)
+++ struts/struts2/trunk/core/src/site/resources/tags/number.html Wed Dec 28 21:47:20 2011
@@ -0,0 +1,136 @@
+<!--
+This file is generated during the build by processing Component class annotations.
+Please do not edit it directly.
+-->
+<html>
+    <head>
+		<title>number</title>
+	</head>
+
+	<body>
+		<h1>Tag Name: number</h1>
+		<h2>Description</h2>
+		<p>
+		<!-- START SNIPPET: tagdescription -->
+		Render a formatted number.
+		<!-- END SNIPPET: tagdescription -->
+		</p>
+
+		<h2>Attributes</h2>
+		<!-- START SNIPPET: tagattributes -->
+		<table width="100%">
+			<tr>
+				<td colspan="6"><h4>Dynamic Attributes Allowed:</h4> false</td>
+			</tr>
+			<tr>
+				<td colspan="6">&nbsp;</td>
+			</tr>
+			<tr>
+				<th align="left" valign="top"><h4>Name</h4></th>
+				<th align="left" valign="top"><h4>Required</h4></th>
+				<th align="left" valign="top"><h4>Default</h4></th>
+				<th align="left" valign="top"><h4>Evaluated</h4></th>
+				<th align="left" valign="top"><h4>Type</h4></th>
+				<th align="left" valign="top"><h4>Description</h4></th>
+			</tr>
+				<tr>
+					<td align="left" valign="top">currency</td>
+					<td align="left" valign="top">false</td>
+					<td align="left" valign="top"></td>
+					<td align="left" valign="top">false</td>
+					<td align="left" valign="top">String</td>
+					<td align="left" valign="top">The currency to use for a currency format</td>
+				</tr>
+				<tr>
+					<td align="left" valign="top">groupingUsed</td>
+					<td align="left" valign="top">false</td>
+					<td align="left" valign="top"></td>
+					<td align="left" valign="top">false</td>
+					<td align="left" valign="top">Boolean</td>
+					<td align="left" valign="top">Whether grouping is used</td>
+				</tr>
+				<tr>
+					<td align="left" valign="top">id</td>
+					<td align="left" valign="top">false</td>
+					<td align="left" valign="top"></td>
+					<td align="left" valign="top">false</td>
+					<td align="left" valign="top">String</td>
+					<td align="left" valign="top">Deprecated. Use 'var' instead</td>
+				</tr>
+				<tr>
+					<td align="left" valign="top">maximumFractionDigits</td>
+					<td align="left" valign="top">false</td>
+					<td align="left" valign="top"></td>
+					<td align="left" valign="top">false</td>
+					<td align="left" valign="top">Integer</td>
+					<td align="left" valign="top">Maximum fraction digits</td>
+				</tr>
+				<tr>
+					<td align="left" valign="top">maximumIntegerDigits</td>
+					<td align="left" valign="top">false</td>
+					<td align="left" valign="top"></td>
+					<td align="left" valign="top">false</td>
+					<td align="left" valign="top">Integer</td>
+					<td align="left" valign="top">Maximum integer digits</td>
+				</tr>
+				<tr>
+					<td align="left" valign="top">minimumFractionDigits</td>
+					<td align="left" valign="top">false</td>
+					<td align="left" valign="top"></td>
+					<td align="left" valign="top">false</td>
+					<td align="left" valign="top">Integer</td>
+					<td align="left" valign="top">Minimum fraction digits</td>
+				</tr>
+				<tr>
+					<td align="left" valign="top">minimumIntegerDigits</td>
+					<td align="left" valign="top">false</td>
+					<td align="left" valign="top"></td>
+					<td align="left" valign="top">false</td>
+					<td align="left" valign="top">Integer</td>
+					<td align="left" valign="top">Maximum integer digits</td>
+				</tr>
+				<tr>
+					<td align="left" valign="top">name</td>
+					<td align="left" valign="top"><strong>true</strong></td>
+					<td align="left" valign="top"></td>
+					<td align="left" valign="top">false</td>
+					<td align="left" valign="top">String</td>
+					<td align="left" valign="top">The number value to format</td>
+				</tr>
+				<tr>
+					<td align="left" valign="top">parseIntegerOnly</td>
+					<td align="left" valign="top">false</td>
+					<td align="left" valign="top"></td>
+					<td align="left" valign="top">false</td>
+					<td align="left" valign="top">Boolean</td>
+					<td align="left" valign="top">Parse integer only</td>
+				</tr>
+				<tr>
+					<td align="left" valign="top">roundingMode</td>
+					<td align="left" valign="top">false</td>
+					<td align="left" valign="top"></td>
+					<td align="left" valign="top">false</td>
+					<td align="left" valign="top">String</td>
+					<td align="left" valign="top">The rounding mode to use</td>
+				</tr>
+				<tr>
+					<td align="left" valign="top">type</td>
+					<td align="left" valign="top">false</td>
+					<td align="left" valign="top"></td>
+					<td align="left" valign="top">false</td>
+					<td align="left" valign="top">String</td>
+					<td align="left" valign="top">Type of number formatter (currency, integer, number or percent, default is number)</td>
+				</tr>
+				<tr>
+					<td align="left" valign="top">var</td>
+					<td align="left" valign="top">false</td>
+					<td align="left" valign="top"></td>
+					<td align="left" valign="top">false</td>
+					<td align="left" valign="top">String</td>
+					<td align="left" valign="top">Name used to reference the value pushed into the Value Stack</td>
+				</tr>
+		</table>
+		<!-- END SNIPPET: tagattributes -->
+	</body>
+</html>
+

Modified: struts/struts2/trunk/core/src/test/java/org/apache/struts2/TestAction.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/test/java/org/apache/struts2/TestAction.java?rev=1225353&r1=1225352&r2=1225353&view=diff
==============================================================================
--- struts/struts2/trunk/core/src/test/java/org/apache/struts2/TestAction.java (original)
+++ struts/struts2/trunk/core/src/test/java/org/apache/struts2/TestAction.java Wed Dec 28 21:47:20 2011
@@ -21,13 +21,16 @@
 
 package org.apache.struts2;
 
-import java.util.*;
-
-import org.apache.struts2.views.jsp.ui.User;
-
 import com.opensymphony.xwork2.Action;
 import com.opensymphony.xwork2.ActionSupport;
 import com.opensymphony.xwork2.util.ValueStack;
+import org.apache.struts2.views.jsp.ui.User;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 
 /**
@@ -48,6 +51,7 @@ public class TestAction extends ActionSu
     private List list2;
     private List list3;
     private SomeEnum status = SomeEnum.COMPLETED;
+    private Float floatNumber;
 
     private final Map<String, String> texts = new HashMap<String, String>();
 
@@ -197,4 +201,11 @@ public class TestAction extends ActionSu
     	return Arrays.asList(SomeEnum.values());
     }
 
+    public Float getFloatNumber() {
+        return floatNumber;
+    }
+
+    public void setFloatNumber(Float floatNumber) {
+        this.floatNumber = floatNumber;
+    }
 }

Added: struts/struts2/trunk/core/src/test/java/org/apache/struts2/views/jsp/NumberTagTest.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/test/java/org/apache/struts2/views/jsp/NumberTagTest.java?rev=1225353&view=auto
==============================================================================
--- struts/struts2/trunk/core/src/test/java/org/apache/struts2/views/jsp/NumberTagTest.java (added)
+++ struts/struts2/trunk/core/src/test/java/org/apache/struts2/views/jsp/NumberTagTest.java Wed Dec 28 21:47:20 2011
@@ -0,0 +1,99 @@
+package org.apache.struts2.views.jsp;
+
+import com.opensymphony.xwork2.ActionContext;
+import org.apache.struts2.TestAction;
+
+import java.math.RoundingMode;
+import java.text.NumberFormat;
+import java.util.Locale;
+
+public class NumberTagTest extends AbstractTagTest {
+
+    public void testSimpleFloatFormat() throws Exception {
+        // given
+        context.put(ActionContext.LOCALE, Locale.US);
+
+        TestAction testAction = (TestAction) action;
+        testAction.setFloatNumber(120.0f);
+
+        NumberTag tag = new NumberTag();
+        tag.setPageContext(pageContext);
+        tag.setName("floatNumber");
+
+        // when
+        tag.doStartTag();
+        tag.doEndTag();
+
+        // then
+        assertEquals("120", writer.toString());
+    }
+    
+    public void testSimpleCurrencyUSFormat() throws Exception {
+        // given
+        context.put(ActionContext.LOCALE, Locale.US);
+        
+        TestAction testAction = (TestAction) action;
+        testAction.setFloatNumber(120.0f);
+
+        NumberTag tag = new NumberTag();
+        tag.setPageContext(pageContext);
+        tag.setName("floatNumber");
+        tag.setType("currency");
+
+        // when
+        tag.doStartTag();
+        tag.doEndTag();
+
+        // then
+        assertEquals("$120.00", writer.toString());
+    }
+    
+    public void testSimpleCurrencyPLFormat() throws Exception {
+        // given
+        context.put(ActionContext.LOCALE, new Locale("pl", "PL"));
+        
+        TestAction testAction = (TestAction) action;
+        testAction.setFloatNumber(120.0f);
+
+        NumberTag tag = new NumberTag();
+        tag.setPageContext(pageContext);
+        tag.setName("floatNumber");
+        tag.setType("currency");
+
+        // when
+        tag.doStartTag();
+        tag.doEndTag();
+
+        // then
+        NumberFormat format = NumberFormat.getCurrencyInstance((Locale) context.get(ActionContext.LOCALE));
+        format.setRoundingMode(RoundingMode.CEILING);
+        String expected = format.format(120.0f);
+
+        assertEquals(expected, writer.toString());
+    }
+
+    public void testSimpleRoundingCeiling() throws Exception {
+        // given
+        context.put(ActionContext.LOCALE, Locale.US);
+
+        TestAction testAction = (TestAction) action;
+        testAction.setFloatNumber(120.45f);
+
+        NumberTag tag = new NumberTag();
+        tag.setPageContext(pageContext);
+        tag.setName("floatNumber");
+        tag.setRoundingMode("ceiling");
+
+        // when
+        tag.doStartTag();
+        tag.doEndTag();
+
+        // then
+        NumberFormat format = NumberFormat.getInstance((Locale) context.get(ActionContext.LOCALE));
+        format.setRoundingMode(RoundingMode.CEILING);
+        String expected = format.format(120.45f);
+
+        assertEquals(expected, writer.toString());
+    }
+
+}