/** * AnalyzerBeans * Copyright (C) 2014 Neopost - Customer Information Management * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU * Lesser General Public License, as published by the Free Software Foundation. * * 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. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution; if not, write to: * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ package org.eobjects.analyzer.beans.coalesce; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.eobjects.analyzer.beans.api.Alias; import org.eobjects.analyzer.beans.api.Categorized; import org.eobjects.analyzer.beans.api.Configured; import org.eobjects.analyzer.beans.api.Description; import org.eobjects.analyzer.beans.api.OutputColumns; import org.eobjects.analyzer.beans.api.Transformer; import org.eobjects.analyzer.beans.api.TransformerBean; import org.eobjects.analyzer.beans.categories.CompositionCategory; import org.eobjects.analyzer.data.InputColumn; import org.eobjects.analyzer.data.InputRow; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @TransformerBean("Fuse / Coalesce fields") @Alias("Coalesce multiple fields") @Description("Lets you combine multiple fields into one, selecting the first value that is non-null.\n\n" + "Use it to fuse data streams coming from different filter requirements. You can define new fields whose values represent whatever is available from one of the input streams.\n\n" + "Or use it to identify the most accurate or most recent observation, if multiple entries have been recorded in separate columns.") @Categorized(CompositionCategory.class) public class CoalesceMultipleFieldsTransformer implements Transformer<Object> { private static final Logger logger = LoggerFactory.getLogger(CoalesceMultipleFieldsTransformer.class); @Configured InputColumn<?>[] _input; @Configured CoalesceUnit[] _units; @Configured @Description("Consider empty strings (\"\") as null also?") boolean considerEmptyStringAsNull = true; public CoalesceMultipleFieldsTransformer() { } public CoalesceMultipleFieldsTransformer(CoalesceUnit... units) { this(); this._units = units; } /** * Configures the transformer using the coalesce units provided * * @param units */ public void configureUsingCoalesceUnits(CoalesceUnit... units) { final List<InputColumn<?>> input = new ArrayList<InputColumn<?>>(); for (CoalesceUnit coalesceUnit : units) { final InputColumn<?>[] inputColumns = coalesceUnit.getInputColumns(null); for (final InputColumn<?> inputColumn : inputColumns) { input.add(inputColumn); } } _input = input.toArray(new InputColumn[input.size()]); _units = units; } @Override public OutputColumns getOutputColumns() { final OutputColumns outputColumns = new OutputColumns(_units.length); for (int i = 0; i < _units.length; i++) { final CoalesceUnit unit = _units[i]; final Class<?> dataType = unit.getOutputDataType(_input); outputColumns.setColumnType(i, dataType); } return outputColumns; } @Override public Object[] transform(InputRow inputRow) { final Object[] result = new Object[_units.length]; for (int i = 0; i < _units.length; i++) { final CoalesceUnit unit = _units[i]; final InputColumn<?>[] inputColumns = unit.getInputColumns(_input); final List<Object> values = inputRow.getValues(inputColumns); final Object value = coalesce(values); result[i] = value; } if (logger.isDebugEnabled()) { logger.debug("Coalesced values for row {}: {}", inputRow.getId(), Arrays.toString(result)); } return result; } private Object coalesce(List<Object> values) { for (final Object value : values) { if (value != null) { if (considerEmptyStringAsNull) { if (!"".equals(value)) { return value; } } else { return value; } } } return null; } }