001    /**
002     * ========================================
003     * JFreeReport : a free Java report library
004     * ========================================
005     *
006     * Project Info:  http://reporting.pentaho.org/
007     *
008     * (C) Copyright 2000-2007, by Object Refinery Limited, Pentaho Corporation and Contributors.
009     *
010     * This library is free software; you can redistribute it and/or modify it under the terms
011     * of the GNU Lesser General Public License as published by the Free Software Foundation;
012     * either version 2.1 of the License, or (at your option) any later version.
013     *
014     * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
015     * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016     * See the GNU Lesser General Public License for more details.
017     *
018     * You should have received a copy of the GNU Lesser General Public License along with this
019     * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
020     * Boston, MA 02111-1307, USA.
021     *
022     * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
023     * in the United States and other countries.]
024     *
025     * ------------
026     * $Id: MessageFormatSupport.java 3525 2007-10-16 11:43:48Z tmorgner $
027     * ------------
028     * (C) Copyright 2000-2005, by Object Refinery Limited.
029     * (C) Copyright 2005-2007, by Pentaho Corporation.
030     */
031    package org.jfree.report.util;
032    
033    import java.io.Serializable;
034    import java.text.DateFormat;
035    import java.text.Format;
036    import java.text.MessageFormat;
037    import java.text.NumberFormat;
038    import java.util.ArrayList;
039    import java.util.Date;
040    import java.util.Locale;
041    
042    import org.jfree.report.DataRow;
043    import org.jfree.report.DataSourceException;
044    
045    public class MessageFormatSupport implements Serializable, Cloneable
046    {
047      protected static class MessageCompiler extends PropertyLookupParser
048      {
049        private ArrayList fields;
050        //private ArrayList completeFormatString;
051    
052        protected MessageCompiler()
053        {
054          this.fields = new ArrayList();
055          //this.completeFormatString = new ArrayList();
056          setMarkerChar('$');
057          setOpeningBraceChar('(');
058          setClosingBraceChar(')');
059        }
060    
061        protected String lookupVariable(final String name)
062        {
063          final CSVTokenizer tokenizer = new CSVTokenizer(name, ",", "\"");
064          if (tokenizer.hasMoreTokens() == false)
065          {
066            return null;
067          }
068          final String varName = tokenizer.nextToken();
069    /*    // we have to collect every occurence, even if it is included twice
070          // to allow the null-value-processing later ..
071          final int index = fields.indexOf(varName);
072          if (index != -1)
073          {
074            return (String) completeFormatString.get(index);
075          }
076    */
077          final StringBuffer b = new StringBuffer();
078          b.append("{");
079          b.append(String.valueOf(fields.size()));
080          while (tokenizer.hasMoreTokens())
081          {
082            b.append(",");
083            b.append(tokenizer.nextToken());
084          }
085          b.append("}");
086          final String formatString = b.toString();
087          //completeFormatString.add(formatString);
088          fields.add(varName);
089          return formatString;
090        }
091    
092        public String[] getFields()
093        {
094          return (String[]) fields.toArray(new String[fields.size()]);
095        }
096      }
097    
098      private String[] fields;
099      private MessageFormat format;
100      private String formatString;
101      private String compiledFormat;
102      private String nullString;
103    
104      public MessageFormatSupport()
105      {
106      }
107    
108      public String getFormatString()
109      {
110        return formatString;
111      }
112    
113      public void setFormatString(final String formatString)
114      {
115        final MessageCompiler compiler = new MessageCompiler();
116        if (formatString == null)
117        {
118          throw new NullPointerException("Format must not be null");
119        }
120        compiledFormat = compiler.translateAndLookup(formatString);
121        fields = compiler.getFields();
122        format = new MessageFormat(compiledFormat);
123        this.formatString = formatString;
124      }
125    
126      public String performFormat(final DataRow dataRow) throws DataSourceException
127      {
128        return formatWithReplace(dataRow, format, fields, nullString);
129      }
130    
131      public Locale getLocale()
132      {
133        return format.getLocale();
134      }
135    
136      public String getCompiledFormat()
137      {
138        return compiledFormat;
139      }
140    
141      public void setLocale(final Locale locale)
142      {
143        format.setLocale(locale);
144        format.applyPattern(compiledFormat);
145      }
146    
147      public String getNullString()
148      {
149        return nullString;
150      }
151    
152      public void setNullString(final String nullString)
153      {
154        this.nullString = nullString;
155      }
156    
157      public Object clone()
158              throws CloneNotSupportedException
159      {
160        final MessageFormatSupport support = (MessageFormatSupport) super.clone();
161        if (format != null)
162        {
163          support.format = (MessageFormat) format.clone();
164        }
165        return support;
166      }
167    
168      public String[] getFields()
169      {
170        return (String[]) fields.clone();
171      }
172    
173    
174      public static String formatWithReplace(final DataRow dataRow,
175                                             final MessageFormat format,
176                                             final String[] fields,
177                                             final String nullString)
178              throws DataSourceException
179      {
180        if (fields == null || format == null)
181        {
182          return null;
183        }
184    
185        final boolean fastProcessingPossible = (nullString == null);
186    
187        final Format[] formats = format.getFormats();
188        boolean fastProcessing = true;
189        final Object[] parameters = new Object[fields.length];
190        final boolean[] replaced = new boolean[fields.length];
191        for (int i = 0; i < parameters.length; i++)
192        {
193          final Object value = dataRow.get(fields[i]);
194          final Format currentFormat = formats[i];
195          if (value == null)
196          {
197            parameters[i] = nullString;
198            replaced[i] = currentFormat != null;
199            fastProcessing = (fastProcessing && fastProcessingPossible && replaced[i] == false);
200          }
201          else
202          {
203            if (currentFormat instanceof DateFormat)
204            {
205              if (value instanceof Date)
206              {
207                parameters[i] = value;
208                replaced[i] = false;
209              }
210              else
211              {
212                parameters[i] = nullString;
213                replaced[i] = true;
214                fastProcessing = (fastProcessing && fastProcessingPossible && replaced[i] == false);
215              }
216            }
217            else if (currentFormat instanceof NumberFormat)
218            {
219              if (value instanceof Number)
220              {
221                parameters[i] = value;
222                replaced[i] = false;
223              }
224              else
225              {
226                parameters[i] = nullString;
227                replaced[i] = true;
228                fastProcessing = (fastProcessing && fastProcessingPossible && replaced[i] == false);
229              }
230            }
231            else
232            {
233              parameters[i] = value;
234              replaced[i] = false;
235            }
236          }
237        }
238        if (fastProcessing)
239        {
240          return format.format(parameters);
241        }
242    
243        final MessageFormat effectiveFormat = (MessageFormat) format.clone();
244        for (int i = 0; i < replaced.length; i++)
245        {
246          final boolean b = replaced[i];
247          if (b)
248          {
249            effectiveFormat.setFormat(i, null);
250          }
251        }
252        return effectiveFormat.format(parameters);
253      }
254    
255    
256      public static String formatWithReplace(final MessageFormat format,
257                                             final Object[] inputValues,
258                                             final String nullString)
259      {
260        if (inputValues == null || format == null)
261        {
262          return null;
263        }
264    
265        final Object[] values = (Object[]) inputValues.clone();
266    
267        final boolean fastProcessingPossible = (nullString == null);
268    
269        final Format[] formats = format.getFormats();
270        boolean fastProcessing = true;
271        final boolean[] replaced = new boolean[values.length];
272        for (int i = 0; i < values.length; i++)
273        {
274          final Object value = values[i];
275          final Format currentFormat = formats[i];
276          if (value == null)
277          {
278            values[i] = nullString;
279            replaced[i] = currentFormat != null;
280            fastProcessing = (fastProcessing && fastProcessingPossible && replaced[i] == false);
281          }
282          else
283          {
284            if (currentFormat instanceof DateFormat)
285            {
286              if (value instanceof Date)
287              {
288                values[i] = value;
289                replaced[i] = false;
290              }
291              else
292              {
293                values[i] = nullString;
294                replaced[i] = true;
295                fastProcessing = (fastProcessing && fastProcessingPossible && replaced[i] == false);
296              }
297            }
298            else if (currentFormat instanceof NumberFormat)
299            {
300              if (value instanceof Number)
301              {
302                values[i] = value;
303                replaced[i] = false;
304              }
305              else
306              {
307                values[i] = nullString;
308                replaced[i] = true;
309                fastProcessing = (fastProcessing && fastProcessingPossible && replaced[i] == false);
310              }
311            }
312            else
313            {
314              values[i] = value;
315              replaced[i] = false;
316            }
317          }
318        }
319        if (fastProcessing)
320        {
321          return format.format(values);
322        }
323    
324        final MessageFormat effectiveFormat = (MessageFormat) format.clone();
325        for (int i = 0; i < replaced.length; i++)
326        {
327          final boolean b = replaced[i];
328          if (b)
329          {
330            effectiveFormat.setFormat(i, null);
331          }
332        }
333        return effectiveFormat.format(values);
334      }
335    
336    }