1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the  "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 *     http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18/*
19 * $Id: FuncFormatNumb.java 468643 2006-10-28 06:56:03Z minchau $
20 */
21package org.apache.xalan.templates;
22
23import javax.xml.transform.ErrorListener;
24import javax.xml.transform.TransformerException;
25
26import org.apache.xalan.res.XSLMessages;
27import org.apache.xalan.res.XSLTErrorResources;
28import org.apache.xml.utils.QName;
29import org.apache.xml.utils.SAXSourceLocator;
30import org.apache.xpath.Expression;
31import org.apache.xpath.XPathContext;
32import org.apache.xpath.functions.Function3Args;
33import org.apache.xpath.functions.WrongNumberArgsException;
34import org.apache.xpath.objects.XObject;
35import org.apache.xpath.objects.XString;
36
37/**
38 * Execute the FormatNumber() function.
39 * @xsl.usage advanced
40 */
41public class FuncFormatNumb extends Function3Args
42{
43    static final long serialVersionUID = -8869935264870858636L;
44
45  /**
46   * Execute the function.  The function must return
47   * a valid object.
48   * @param xctxt The current execution context.
49   * @return A valid XObject.
50   *
51   * @throws javax.xml.transform.TransformerException
52   */
53  public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException
54  {
55
56    // A bit of an ugly hack to get our context.
57    ElemTemplateElement templElem =
58      (ElemTemplateElement) xctxt.getNamespaceContext();
59    StylesheetRoot ss = templElem.getStylesheetRoot();
60    java.text.DecimalFormat formatter = null;
61    java.text.DecimalFormatSymbols dfs = null;
62    double num = getArg0().execute(xctxt).num();
63    String patternStr = getArg1().execute(xctxt).str();
64
65    // TODO: what should be the behavior here??
66    if (patternStr.indexOf(0x00A4) > 0)
67      ss.error(XSLTErrorResources.ER_CURRENCY_SIGN_ILLEGAL);  // currency sign not allowed
68
69    // this third argument is not a locale name. It is the name of a
70    // decimal-format declared in the stylesheet!(xsl:decimal-format
71    try
72    {
73      Expression arg2Expr = getArg2();
74
75      if (null != arg2Expr)
76      {
77        String dfName = arg2Expr.execute(xctxt).str();
78        QName qname = new QName(dfName, xctxt.getNamespaceContext());
79
80        dfs = ss.getDecimalFormatComposed(qname);
81
82        if (null == dfs)
83        {
84          warn(xctxt, XSLTErrorResources.WG_NO_DECIMALFORMAT_DECLARATION,
85               new Object[]{ dfName });  //"not found!!!
86
87          //formatter = new java.text.DecimalFormat(patternStr);
88        }
89        else
90        {
91
92          //formatter = new java.text.DecimalFormat(patternStr, dfs);
93          formatter = new java.text.DecimalFormat();
94
95          formatter.setDecimalFormatSymbols(dfs);
96          formatter.applyLocalizedPattern(patternStr);
97        }
98      }
99
100      //else
101      if (null == formatter)
102      {
103
104        // look for a possible default decimal-format
105        dfs = ss.getDecimalFormatComposed(new QName(""));
106
107        if (dfs != null)
108        {
109          formatter = new java.text.DecimalFormat();
110
111          formatter.setDecimalFormatSymbols(dfs);
112          formatter.applyLocalizedPattern(patternStr);
113        }
114        else
115        {
116          dfs = new java.text.DecimalFormatSymbols(java.util.Locale.US);
117
118          dfs.setInfinity(Constants.ATTRVAL_INFINITY);
119          dfs.setNaN(Constants.ATTRVAL_NAN);
120
121          formatter = new java.text.DecimalFormat();
122
123          formatter.setDecimalFormatSymbols(dfs);
124
125          if (null != patternStr)
126            formatter.applyLocalizedPattern(patternStr);
127        }
128      }
129
130      return new XString(formatter.format(num));
131    }
132    catch (Exception iae)
133    {
134      templElem.error(XSLTErrorResources.ER_MALFORMED_FORMAT_STRING,
135                      new Object[]{ patternStr });
136
137      return XString.EMPTYSTRING;
138
139      //throw new XSLProcessorException(iae);
140    }
141  }
142
143  /**
144   * Warn the user of a problem.
145   *
146   * @param xctxt The XPath runtime state.
147   * @param msg Warning message key
148   * @param args Arguments to be used in warning message
149   * @throws XSLProcessorException thrown if the active ProblemListener and XPathContext decide
150   * the error condition is severe enough to halt processing.
151   *
152   * @throws javax.xml.transform.TransformerException
153   */
154  public void warn(XPathContext xctxt, String msg, Object args[])
155          throws javax.xml.transform.TransformerException
156  {
157
158    String formattedMsg = XSLMessages.createWarning(msg, args);
159    ErrorListener errHandler = xctxt.getErrorListener();
160
161    errHandler.warning(new TransformerException(formattedMsg,
162                                             (SAXSourceLocator)xctxt.getSAXLocator()));
163  }
164
165  /**
166   * Overide the superclass method to allow one or two arguments.
167   *
168   *
169   * @param argNum Number of arguments passed in
170   *
171   * @throws WrongNumberArgsException
172   */
173  public void checkNumberArgs(int argNum) throws WrongNumberArgsException
174  {
175    if ((argNum > 3) || (argNum < 2))
176      reportWrongNumberArgs();
177  }
178
179  /**
180   * Constructs and throws a WrongNumberArgException with the appropriate
181   * message for this function object.
182   *
183   * @throws WrongNumberArgsException
184   */
185  protected void reportWrongNumberArgs() throws WrongNumberArgsException {
186      throw new WrongNumberArgsException(XSLMessages.createMessage(XSLTErrorResources.ER_TWO_OR_THREE, null)); //"2 or 3");
187  }
188}
189