001: /**
002: * ===========================================
003: * JFreeReport : a free Java reporting library
004: * ===========================================
005: *
006: * Project Info: http://reporting.pentaho.org/
007: *
008: * (C) Copyright 2001-2007, by Object Refinery Ltd, 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: * MessageFormatExpression.java
027: * ------------
028: * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
029: */package org.jfree.report.function.strings;
030:
031: import java.io.UnsupportedEncodingException;
032: import java.util.Date;
033:
034: import org.jfree.report.DataRow;
035: import org.jfree.report.ResourceBundleFactory;
036: import org.jfree.report.filter.MessageFormatSupport;
037: import org.jfree.report.function.AbstractExpression;
038: import org.jfree.report.function.Expression;
039: import org.jfree.report.util.UTFEncodingUtil;
040: import org.jfree.util.Log;
041:
042: /**
043: * Formats a message read from a resource-bundle using named parameters. The parameters are resolved against the current
044: * data-row.
045: * <p/>
046: * This performs the same task as the ResourceMessageFormatFilter does inside a text-element.
047: *
048: * @author Thomas Morgner
049: */
050: public class MessageFormatExpression extends AbstractExpression {
051: /**
052: * A internal data-row wrapper that URL-encodes all values returned by the data-row.
053: */
054: private static class EncodeDataRow implements DataRow {
055: /** The wrappedDataRow datarow. */
056: private DataRow wrappedDataRow;
057: /** The character encoding used for the URL-encoding. */
058: private String encoding;
059:
060: /**
061: * Default Constructor.
062: */
063: protected EncodeDataRow() {
064: }
065:
066: /**
067: * Returns the wrapped data-row.
068: * @return the wrapped data-row.
069: */
070: public DataRow getWrappedDataRow() {
071: return wrappedDataRow;
072: }
073:
074: /**
075: * Defines the wrapped data-row.
076: *
077: * @param wrappedDataRow the wrapped datarow.
078: */
079: public void setWrappedDataRow(final DataRow wrappedDataRow) {
080: this .wrappedDataRow = wrappedDataRow;
081: }
082:
083: /**
084: * Returns the String-encoding used for the URL encoding.
085: * @return the string-encoding.
086: */
087: public String getEncoding() {
088: return encoding;
089: }
090:
091: /**
092: * Defines the String-encoding used for the URL encoding.
093: * @param encoding the string-encoding.
094: */
095: public void setEncoding(final String encoding) {
096: this .encoding = encoding;
097: }
098:
099: /**
100: * Encodes the given value. The encoding process is skipped, if the value is null, is a number or is a date.
101: *
102: * @param fieldValue the value that should be encoded.
103: * @return the encoded value.
104: */
105: private Object encode(final Object fieldValue) {
106: if (fieldValue == null) {
107: return null;
108: }
109: if (fieldValue instanceof Date) {
110: return fieldValue;
111: } else if (fieldValue instanceof Number) {
112: return fieldValue;
113: }
114: try {
115: return UTFEncodingUtil.encode(String
116: .valueOf(fieldValue), encoding);
117: } catch (UnsupportedEncodingException e) {
118: Log.debug("Unsupported Encoding: " + encoding);
119: return null;
120: }
121: }
122:
123: /**
124: * Returns the value of the expression or column in the data-row using the given
125: * column number as index.
126: *
127: * @param col the item index.
128: * @return the value.
129: * @throws IllegalStateException if the datarow detected a deadlock.
130: */
131: public Object get(final int col) {
132: return encode(wrappedDataRow.get(col));
133: }
134:
135: /**
136: * Returns the value of the function, expression or column using its specific name. The
137: * given name is translated into a valid column number and the the column is queried.
138: * For functions and expressions, the <code>getValue()</code> method is called and for
139: * columns from the tablemodel the tablemodel method <code>getValueAt(row,
140: * column)</code> gets called.
141: *
142: * @param col the item index.
143: * @return the value.
144: *
145: * @throws IllegalStateException if the datarow detected a deadlock.
146: */
147: public Object get(final String col)
148: throws IllegalStateException {
149: return encode(wrappedDataRow.get(col));
150: }
151:
152: /**
153: * Returns the name of the column, expression or function. For columns from the
154: * tablemodel, the tablemodels <code>getColumnName</code> method is called. For
155: * functions, expressions and report properties the assigned name is returned.
156: *
157: * @param col the item index.
158: * @return the name.
159: */
160: public String getColumnName(final int col) {
161: return wrappedDataRow.getColumnName(col);
162: }
163:
164: /**
165: * Returns the column position of the column, expression or function with the given name
166: * or -1 if the given name does not exist in this DataRow.
167: *
168: * @param name the item name.
169: * @return the item index.
170: */
171: public int findColumn(final String name) {
172: return wrappedDataRow.findColumn(name);
173: }
174:
175: /**
176: * Returns the number of columns, expressions and functions and marked ReportProperties
177: * in the report.
178: *
179: * @return the item count.
180: */
181: public int getColumnCount() {
182: return wrappedDataRow.getColumnCount();
183: }
184:
185: /**
186: * Checks, whether the value contained in the column has changed since the
187: * last advance-operation.
188: *
189: * @param name the name of the column.
190: * @return true, if the value has changed, false otherwise.
191: */
192: public boolean isChanged(final String name) {
193: return wrappedDataRow.isChanged(name);
194: }
195:
196: /**
197: * Checks, whether the value contained in the column has changed since the
198: * last advance-operation.
199: *
200: * @param index the numerical index of the column to check.
201: * @return true, if the value has changed, false otherwise.
202: */
203: public boolean isChanged(final int index) {
204: return wrappedDataRow.isChanged(index);
205: }
206: }
207:
208: /**
209: * The message-format pattern used to compute the result.
210: */
211: private String pattern;
212:
213: /**
214: * The message format support translates raw message strings into useable MessageFormat parameters and read the
215: * necessary input data from the datarow.
216: */
217: private MessageFormatSupport messageFormatSupport;
218: /**
219: * A flag indicating whether the data read from the fields should be URL encoded.
220: */
221: private boolean urlEncodeData;
222: /**
223: * A flag indicating whether the whole result string should be URL encoded.
224: */
225: private boolean urlEncodeResult;
226: /**
227: * The byte-encoding used for the URL encoding.
228: */
229: private String encoding;
230:
231: /**
232: * Default constructor.
233: */
234: public MessageFormatExpression() {
235: messageFormatSupport = new MessageFormatSupport();
236: encoding = "ISO-8859-1";
237: }
238:
239: /**
240: * Returns the format string used in the message format.
241: *
242: * @return the format string.
243: */
244: public String getPattern() {
245: return pattern;
246: }
247:
248: /**
249: * Defines the format string for the {@link java.text.MessageFormat} object used in this implementation.
250: *
251: * @param pattern the message format.
252: */
253: public void setPattern(final String pattern) {
254: this .pattern = pattern;
255: }
256:
257: /**
258: * Returns the defined character encoding that is used to transform the Java-Unicode strings into bytes.
259: *
260: * @return the encoding.
261: */
262: public String getEncoding() {
263: return encoding;
264: }
265:
266: /**
267: * Defines the character encoding that is used to transform the Java-Unicode strings into bytes.
268: *
269: * @param encoding the encoding.
270: */
271: public void setEncoding(final String encoding) {
272: if (encoding == null) {
273: throw new NullPointerException();
274: }
275: this .encoding = encoding;
276: }
277:
278: /**
279: * Defines, whether the values read from the data-row should be URL encoded. Dates and Number objects are never
280: * encoded.
281: *
282: * @param urlEncode true, if the values from the data-row should be URL encoded before they are passed to the
283: * MessageFormat, false otherwise.
284: */
285: public void setUrlEncodeValues(final boolean urlEncode) {
286: this .urlEncodeData = urlEncode;
287: }
288:
289: /**
290: * Queries, whether the values read from the data-row should be URL encoded.
291: *
292: * @return true, if the values are encoded, false otherwise.
293: */
294: public boolean isUrlEncodeValues() {
295: return urlEncodeData;
296: }
297:
298: /**
299: * Queries, whether the formatted result-string will be URL encoded.
300: *
301: * @return true, if the formatted result will be encoded, false otherwise.
302: */
303: public boolean isUrlEncodeResult() {
304: return urlEncodeResult;
305: }
306:
307: /**
308: * Defines, whether the formatted result-string will be URL encoded.
309: *
310: * @param urlEncodeResult true, if the formatted result will be encoded, false otherwise.
311: */
312: public void setUrlEncodeResult(final boolean urlEncodeResult) {
313: this .urlEncodeResult = urlEncodeResult;
314: }
315:
316: /**
317: * Returns the replacement text that is used if one of the referenced message parameters is null.
318: *
319: * @return the replacement text for null-values.
320: */
321: public String getNullString() {
322: return messageFormatSupport.getNullString();
323: }
324:
325: /**
326: * Defines the replacement text that is used if one of the referenced message parameters is null.
327: *
328: * @param nullString the replacement text for null-values.
329: */
330: public void setNullString(final String nullString) {
331: this .messageFormatSupport.setNullString(nullString);
332: }
333:
334: /**
335: * Returns the formatted message.
336: *
337: * @return the formatted message.
338: */
339: public Object getValue() {
340: final ResourceBundleFactory resourceBundleFactory = getResourceBundleFactory();
341: messageFormatSupport.setFormatString(pattern);
342: messageFormatSupport.setLocale(resourceBundleFactory
343: .getLocale());
344:
345: final String result;
346: if (isUrlEncodeValues()) {
347: final EncodeDataRow dataRow = new EncodeDataRow();
348: dataRow.setEncoding(encoding);
349: dataRow.setWrappedDataRow(getDataRow());
350: result = messageFormatSupport.performFormat(dataRow);
351: } else {
352: result = messageFormatSupport.performFormat(getDataRow());
353: }
354:
355: if (isUrlEncodeResult()) {
356: try {
357: return UTFEncodingUtil.encode(result, getEncoding());
358: } catch (UnsupportedEncodingException e) {
359: Log.debug("Unsupported Encoding: " + encoding);
360: return null;
361: }
362: } else {
363: return result;
364: }
365: }
366:
367: public Expression getInstance() {
368: final MessageFormatExpression ex = (MessageFormatExpression) super
369: .getInstance();
370: ex.messageFormatSupport = new MessageFormatSupport();
371: return ex;
372: }
373: }
|