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,v 1.4 2007/04/01 18:49:33 taqua Exp $
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 public 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(String nullString)
153 {
154 this.nullString = nullString;
155 }
156
157 public Object clone()
158 throws CloneNotSupportedException
159 {
160 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 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 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 Object[] values = (Object[]) inputValues.clone();
266
267 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 boolean b = replaced[i];
328 if (b)
329 {
330 effectiveFormat.setFormat(i, null);
331 }
332 }
333 return effectiveFormat.format(values);
334 }
335
336 }