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: * MapIndirectExpression.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.util.ArrayList;
032: import java.util.Arrays;
033:
034: import org.jfree.report.function.AbstractExpression;
035: import org.jfree.report.function.Expression;
036:
037: /**
038: * Returns the value read from a mapped field. The field's value is used as a key to the field-mapping. The expression
039: * maps the value into a new column name and returns the value read from this column.
040: * <p/>
041: * If the mapping does not exist, then the fallback forward is used instead.
042: *
043: * @author Thomas Morgner
044: */
045: public class MapIndirectExpression extends AbstractExpression {
046: /**
047: * The field from where to read the key value.
048: */
049: private String field;
050: /**
051: * The list of possible keys.
052: */
053: private ArrayList keys;
054: /**
055: * The list of target-fields.
056: */
057: private ArrayList forwards;
058: /**
059: * A flag defining, whether the key-lookup should be case-insensitive.
060: */
061: private boolean ignoreCase;
062: /**
063: * The fallback forward is used if none of the defined keys matches.
064: */
065: private String fallbackForward;
066: /**
067: * The null-value is returned if the key-field evaluates to <code>null</code>.
068: */
069: private String nullValue;
070:
071: /**
072: * Default Constructor.
073: */
074: public MapIndirectExpression() {
075: keys = new ArrayList();
076: forwards = new ArrayList();
077: }
078:
079: /**
080: * Returns the name of the field from where to read the key value.
081: *
082: * @return the field name.
083: */
084: public String getField() {
085: return field;
086: }
087:
088: /**
089: * Defines the name of the field from where to read the key value.
090: *
091: * @param field the field name.
092: */
093: public void setField(final String field) {
094: this .field = field;
095: }
096:
097: /**
098: * Returns the value that is returned if the key-field evaluates to <code>null</code>.
099: *
100: * @return the null-value.
101: */
102: public String getNullValue() {
103: return nullValue;
104: }
105:
106: /**
107: * Defines the value that is returned if the key-field evaluates to <code>null</code>.
108: *
109: * @param nullValue the null-value.
110: */
111: public void setNullValue(final String nullValue) {
112: this .nullValue = nullValue;
113: }
114:
115: /**
116: * Returns the name of the field that is returned if none of the predefined keys matches the lookup-value.
117: *
118: * @return the fallback forward field name.
119: */
120: public String getFallbackForward() {
121: return fallbackForward;
122: }
123:
124: /**
125: * Defines the name of the field that is returned if none of the predefined keys matches the lookup-value.
126: *
127: * @param fallbackForward the fallback forward field name.
128: */
129: public void setFallbackForward(final String fallbackForward) {
130: this .fallbackForward = fallbackForward;
131: }
132:
133: /**
134: * Defines a key value to which the lookup-field's value is compared. If the key is defined, a matching value must be
135: * defined too.
136: *
137: * @param index the index position of the key in the list.
138: * @param key the key value.
139: */
140: public void setKey(final int index, final String key) {
141: if (keys.size() == index) {
142: keys.add(key);
143: } else {
144: keys.set(index, key);
145: }
146: }
147:
148: /**
149: * Returns a key value at the given index.
150: *
151: * @param index the index position of the key in the list.
152: * @return the key value.
153: */
154: public String getKey(final int index) {
155: return (String) keys.get(index);
156: }
157:
158: /**
159: * Returns the number of keys defined in the expression.
160: *
161: * @return the number of keys.
162: */
163: public int getKeyCount() {
164: return keys.size();
165: }
166:
167: /**
168: * Returns all defined keys as string array.
169: *
170: * @return all defined keys.
171: */
172: public String[] getKey() {
173: return (String[]) keys.toArray(new String[keys.size()]);
174: }
175:
176: /**
177: * Defines all keys using the values from the string array.
178: *
179: * @param keys all defined keys.
180: */
181: public void setKey(final String[] keys) {
182: this .keys.clear();
183: this .keys.addAll(Arrays.asList(keys));
184: }
185:
186: /**
187: * Defines the forward-fieldname for the key at the given position. The forward-field is read, if the lookup value
188: * matches the key at this position. The forward-value must be a valid data-row column name.
189: *
190: * @param index the index of the entry.
191: * @param value the name of the datarow-column that is read if the key is selected.
192: */
193: public void setForward(final int index, final String value) {
194: if (forwards.size() == index) {
195: forwards.add(value);
196: } else {
197: forwards.set(index, value);
198: }
199: }
200:
201: /**
202: * Retrieves the forward-fieldname for the key at the given position. The forward-field is read, if the lookup value
203: * matches the key at this position. The forward-value must be a valid data-row column name.
204: *
205: * @param index the index of the entry.
206: * @return the name of the datarow-column that is read if the key is selected.
207: */
208: public String getForward(final int index) {
209: return (String) forwards.get(index);
210: }
211:
212: /**
213: * Returns the number of forward-definitions that have been defined. This should match the number of keys.
214: *
215: * @return the number of forward definitions.
216: */
217: public int getForwardCount() {
218: return forwards.size();
219: }
220:
221: /**
222: * Returns all forward-definitions as string-array.
223: *
224: * @return all forward-definitions.
225: */
226: public String[] getForward() {
227: return (String[]) forwards.toArray(new String[forwards.size()]);
228: }
229:
230: /**
231: * Defiens all forward-definitions using the values of the string-array. The positions in the array must match the key
232: * positions, or funny things will happen.
233: *
234: * @param forwards the forward-name array.
235: */
236: public void setForward(final String[] forwards) {
237: this .forwards.clear();
238: this .forwards.addAll(Arrays.asList(forwards));
239: }
240:
241: /**
242: * Returns, whether the key-lookup should be case-insensitive.
243: *
244: * @return true, if the key comparison is case-insensitive, false otherwise.
245: */
246: public boolean isIgnoreCase() {
247: return ignoreCase;
248: }
249:
250: /**
251: * Defines, whether the key-lookup should be case-insensitive.
252: *
253: * @param ignoreCase true, if the key comparison is case-insensitive, false otherwise.
254: */
255: public void setIgnoreCase(final boolean ignoreCase) {
256: this .ignoreCase = ignoreCase;
257: }
258:
259: /**
260: * Return a completly separated copy of this function. The copy does no longer share any changeable objects with the
261: * original function.
262: *
263: * @return a copy of this function.
264: */
265: public Expression getInstance() {
266: final MapIndirectExpression co = (MapIndirectExpression) super
267: .getInstance();
268: co.forwards = (ArrayList) forwards.clone();
269: co.keys = (ArrayList) keys.clone();
270: return co;
271: }
272:
273: /**
274: * Performs the lookup by first querying the given field, and then mapping the retrived value into one of the
275: * field names.
276: *
277: * @return the value of the function.
278: */
279: public Object getValue() {
280: final Object raw = getDataRow().get(getField());
281: if (raw == null) {
282: return getNullValue();
283: }
284: final String text = String.valueOf(raw);
285: final int length = Math.min(keys.size(), forwards.size());
286: for (int i = 0; i < length; i++) {
287: final String key = (String) keys.get(i);
288: if (isIgnoreCase()) {
289: if (text.equalsIgnoreCase(key)) {
290: final String target = (String) forwards.get(i);
291: return getDataRow().get(target);
292: }
293: } else {
294: if (text.equals(key)) {
295: final String target = (String) forwards.get(i);
296: return getDataRow().get(target);
297: }
298: }
299: }
300: final String fallbackValue = getFallbackForward();
301: if (fallbackValue != null) {
302: return getDataRow().get(fallbackValue);
303: }
304: return raw;
305: }
306: }
|