View Javadoc

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
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  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,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   */
19  package org.apache.myfaces.trinidad.util;
20  
21  import org.apache.myfaces.trinidad.logging.TrinidadLogger;
22  
23  /**
24   * The FastMessageFormat class is a greatly reduced version
25   * of the java.text.MessageFormat class.  It's also much faster
26   * and much less expensive to create, which is especially
27   * valuable when it is created and thrown away many times - 
28   * a common use case in web applications.
29   * <p>
30   * The only syntax supported by this class is simple index-based
31   * replacement, namely:
32   * <pre>
33   *     some{1}text{0}here{2}andthere
34   * </pre>
35   * as well as escaping using single quotes.  Like MessageFormat,
36   * a single quote must be represented using two consecutive single
37   * quotes, but the contents of any text between single quotes
38   * will not be interpreted.  So, the following pattern could
39   * be used to include a left bracket:
40   * <pre>
41   *     some'{'text{0}
42   * </pre>
43   * <p>
44   * @version $Name:  $ ($Revision: adfrt/faces/adf-faces-api/src/main/java/oracle/adf/view/faces/util/FastMessageFormat.java#0 $) $Date: 10-nov-2005.19:08:37 $
45   */
46  public class FastMessageFormat
47  {
48    /**
49     * Creates a FastMessageFormat based on the given format string.
50     */
51    public FastMessageFormat(String formatString)
52    {
53      if (formatString == null)
54        throw new NullPointerException();
55  
56      _formatText = formatString.toCharArray();
57    }
58  
59  
60    /**
61     * Formats the given array of strings based on the initial
62     * pattern.   It is legal for this array to be shorter
63     * than that indicated by the pattern, or to have null
64     * entries - these will simply be ignored.
65     * <p>
66     * @param source an array of strings
67     */
68    public String format(Object[] source)
69    {
70      int formatLength = _formatText.length;
71      int length = 0;
72      int sourceCount = source.length;
73      for (int i = 0; i < sourceCount; i++)
74      {
75        Object sourceString = source[i];
76        if (sourceString != null)
77        {
78          length += sourceString.toString().length();
79        }
80      }
81  
82      StringBuffer buffer = new StringBuffer(length + formatLength);
83  
84      int lastStart = 0;
85      boolean inQuote = false;
86      for (int i = 0; i < formatLength; i++)
87      {
88        char ch = _formatText[i];
89        if (inQuote)
90        {
91          if (ch == '\'')
92          {
93            buffer.append(_formatText, lastStart, i - lastStart);
94            i++;
95            lastStart = i;
96            inQuote = false;
97          }
98        }
99        else
100       {
101         if (ch == '\'')
102         {
103           buffer.append(_formatText, lastStart, i - lastStart);
104           i++;
105           lastStart = i;
106 
107           // Check for doubled-up quotes
108           if ((i < formatLength) && (_formatText[i] == '\''))
109           {
110             // Do nothing;  we'll add the doubled-up quote later
111             ;
112           }
113           else
114           {
115             inQuote = true;
116           }
117         }
118         else if (ch == '{')
119         {
120           buffer.append(_formatText, lastStart, i - lastStart);
121 
122           int sourceIndex = 0;
123           int j = i + 1;
124           for (; j < formatLength; j++)
125           {
126             char patternChar = _formatText[j];
127             if (patternChar == '}')
128             {
129               break;
130             }
131             else
132             {
133               if ((patternChar < '0') ||
134                   (patternChar > '9'))
135                 throw new IllegalArgumentException(_LOG.getLogger().getResourceBundle().getString(
136                   "FASTMESSAGEFORMAT_ONLY_SUPPORT_NUMERIC_ARGUMENTS"));
137               sourceIndex = (sourceIndex * 10) + (patternChar - '0');
138             }
139           }
140 
141           if (j == formatLength)
142             throw new IllegalArgumentException(_LOG.getLogger().getResourceBundle().getString(
143               "END_OF_PATTERN_NOT_FOUND"));
144           if (j == i + 1)
145             throw new IllegalArgumentException(_LOG.getLogger().getResourceBundle().getString(
146               "FASTMESSAGEFORMAT_FIND_EMPTY_ARGUMENT"));
147           if (sourceIndex < sourceCount)
148           {
149             Object sourceString = source[sourceIndex];
150             if (sourceString != null)
151               buffer.append(sourceString.toString());
152           }
153           
154           i = j;
155           lastStart = i + 1;
156         }
157         else
158         {
159            // Do nothing.  The character will be added in later
160           ;
161         }
162       }
163     }
164 
165     buffer.append(_formatText, lastStart, formatLength - lastStart);
166 
167     return new String(buffer);
168   }
169 
170   private final char[] _formatText;
171   private static final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(
172     FastMessageFormat.class);
173 }
174 
175 
176 
177