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 }