/* * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software * Foundation. * * You should have received a copy of the GNU Lesser General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * Copyright (c) 2001 - 2013 Object Refinery Ltd, Pentaho Corporation and Contributors.. All rights reserved. */ package org.pentaho.reporting.engine.classic.core.function.strings; import org.pentaho.reporting.engine.classic.core.function.AbstractExpression; import org.pentaho.reporting.engine.classic.core.function.Expression; import java.util.ArrayList; import java.util.Arrays; /** * Returns the value read from a mapped field. The field's value is used as a key to the field-mapping. The expression * maps the value into a new column name and returns the value read from this column. * <p/> * If the mapping does not exist, then the fallback forward is used instead. * * @author Thomas Morgner */ public class MapIndirectExpression extends AbstractExpression { /** * The field from where to read the key value. */ private String field; /** * The list of possible keys. */ private ArrayList keys; /** * The list of target-fields. */ private ArrayList forwards; /** * A flag defining, whether the key-lookup should be case-insensitive. */ private boolean ignoreCase; /** * The fallback forward is used if none of the defined keys matches. */ private String fallbackForward; /** * The null-value is returned if the key-field evaluates to <code>null</code>. */ private String nullValue; /** * Default Constructor. */ public MapIndirectExpression() { keys = new ArrayList(); forwards = new ArrayList(); } /** * Returns the name of the field from where to read the key value. * * @return the field name. */ public String getField() { return field; } /** * Defines the name of the field from where to read the key value. * * @param field * the field name. */ public void setField( final String field ) { this.field = field; } /** * Returns the value that is returned if the key-field evaluates to <code>null</code>. * * @return the null-value. */ public String getNullValue() { return nullValue; } /** * Defines the value that is returned if the key-field evaluates to <code>null</code>. * * @param nullValue * the null-value. */ public void setNullValue( final String nullValue ) { this.nullValue = nullValue; } /** * Returns the name of the field that is returned if none of the predefined keys matches the lookup-value. * * @return the fallback forward field name. */ public String getFallbackForward() { return fallbackForward; } /** * Defines the name of the field that is returned if none of the predefined keys matches the lookup-value. * * @param fallbackForward * the fallback forward field name. */ public void setFallbackForward( final String fallbackForward ) { this.fallbackForward = fallbackForward; } /** * Defines a key value to which the lookup-field's value is compared. If the key is defined, a matching value must be * defined too. * * @param index * the index position of the key in the list. * @param key * the key value. */ public void setKey( final int index, final String key ) { if ( keys.size() == index ) { keys.add( key ); } else { keys.set( index, key ); } } /** * Returns a key value at the given index. * * @param index * the index position of the key in the list. * @return the key value. */ public String getKey( final int index ) { return (String) keys.get( index ); } /** * Returns the number of keys defined in the expression. * * @return the number of keys. */ public int getKeyCount() { return keys.size(); } /** * Returns all defined keys as string array. * * @return all defined keys. */ public String[] getKey() { return (String[]) keys.toArray( new String[keys.size()] ); } /** * Defines all keys using the values from the string array. * * @param keys * all defined keys. */ public void setKey( final String[] keys ) { this.keys.clear(); this.keys.addAll( Arrays.asList( keys ) ); } /** * Defines the forward-fieldname for the key at the given position. The forward-field is read, if the lookup value * matches the key at this position. The forward-value must be a valid data-row column name. * * @param index * the index of the entry. * @param value * the name of the datarow-column that is read if the key is selected. */ public void setForward( final int index, final String value ) { if ( forwards.size() == index ) { forwards.add( value ); } else { forwards.set( index, value ); } } /** * Retrieves the forward-fieldname for the key at the given position. The forward-field is read, if the lookup value * matches the key at this position. The forward-value must be a valid data-row column name. * * @param index * the index of the entry. * @return the name of the datarow-column that is read if the key is selected. */ public String getForward( final int index ) { return (String) forwards.get( index ); } /** * Returns the number of forward-definitions that have been defined. This should match the number of keys. * * @return the number of forward definitions. */ public int getForwardCount() { return forwards.size(); } /** * Returns all forward-definitions as string-array. * * @return all forward-definitions. */ public String[] getForward() { return (String[]) forwards.toArray( new String[forwards.size()] ); } /** * Defiens all forward-definitions using the values of the string-array. The positions in the array must match the key * positions, or funny things will happen. * * @param forwards * the forward-name array. */ public void setForward( final String[] forwards ) { this.forwards.clear(); this.forwards.addAll( Arrays.asList( forwards ) ); } /** * Returns, whether the key-lookup should be case-insensitive. * * @return true, if the key comparison is case-insensitive, false otherwise. */ public boolean isIgnoreCase() { return ignoreCase; } /** * Defines, whether the key-lookup should be case-insensitive. * * @param ignoreCase * true, if the key comparison is case-insensitive, false otherwise. */ public void setIgnoreCase( final boolean ignoreCase ) { this.ignoreCase = ignoreCase; } /** * Return a completly separated copy of this function. The copy does no longer share any changeable objects with the * original function. * * @return a copy of this function. */ public Expression getInstance() { final MapIndirectExpression co = (MapIndirectExpression) super.getInstance(); co.forwards = (ArrayList) forwards.clone(); co.keys = (ArrayList) keys.clone(); return co; } /** * Performs the lookup by first querying the given field, and then mapping the retrived value into one of the field * names. * * @return the value of the function. */ public Object getValue() { final Object raw = getDataRow().get( getField() ); if ( raw == null ) { return getNullValue(); } final String text = String.valueOf( raw ); final int length = Math.min( keys.size(), forwards.size() ); for ( int i = 0; i < length; i++ ) { final String key = (String) keys.get( i ); if ( isIgnoreCase() ) { if ( text.equalsIgnoreCase( key ) ) { final String target = (String) forwards.get( i ); return getDataRow().get( target ); } } else { if ( text.equals( key ) ) { final String target = (String) forwards.get( i ); return getDataRow().get( target ); } } } final String fallbackValue = getFallbackForward(); if ( fallbackValue != null ) { return getDataRow().get( fallbackValue ); } return raw; } }