All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.datacleaner.panels.fuse.StreamColumnMatrixMultipleCoalesceUnitPropertyWidget Maven / Gradle / Ivy

/**
 * DataCleaner (community edition)
 * Copyright (C) 2014 Free Software Foundation, Inc.
 *
 * 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.datacleaner.panels.fuse;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.swing.BoxLayout;
import javax.swing.JComponent;
import javax.swing.JScrollPane;

import org.apache.metamodel.schema.Table;
import org.datacleaner.api.InputColumn;
import org.datacleaner.api.OutputDataStream;
import org.datacleaner.components.fuse.CoalesceUnit;
import org.datacleaner.data.MutableInputColumn;
import org.datacleaner.descriptors.ConfiguredPropertyDescriptor;
import org.datacleaner.job.builder.AnalysisJobBuilder;
import org.datacleaner.job.builder.ComponentBuilder;
import org.datacleaner.job.builder.TransformerChangeListener;
import org.datacleaner.job.builder.TransformerComponentBuilder;
import org.datacleaner.panels.DCPanel;
import org.datacleaner.util.SourceColumnFinder;
import org.datacleaner.widgets.properties.AbstractPropertyWidget;
import org.datacleaner.widgets.properties.MinimalPropertyWidget;
import org.datacleaner.widgets.properties.PropertyWidget;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;

/**
 * A {@link PropertyWidget} for representing both a property with an array of
 * {@link CoalesceUnit}s and another property with an array of
 * {@link InputColumn}s.
 *
 * This widget presents the incoming streams as columns and available
 * {@link InputColumn}s from each stream as rows in a matrix where the user gets
 * the design a new {@link OutputDataStream}.
 */
public class StreamColumnMatrixMultipleCoalesceUnitPropertyWidget extends AbstractPropertyWidget[]>
        implements TransformerChangeListener, MutableInputColumn.Listener {

    private static final Logger logger =
            LoggerFactory.getLogger(StreamColumnMatrixMultipleCoalesceUnitPropertyWidget.class);

    private final ConfiguredPropertyDescriptor _unitProperty;
    private final MinimalPropertyWidget _unitPropertyWidget;
    private final DCPanel _containerPanel;
    private final List _tablePanels;

    public StreamColumnMatrixMultipleCoalesceUnitPropertyWidget(final ComponentBuilder componentBuilder,
            final ConfiguredPropertyDescriptor inputProperty, final ConfiguredPropertyDescriptor unitProperty) {
        super(componentBuilder, inputProperty);
        _unitProperty = unitProperty;
        _tablePanels = new ArrayList<>();

        getAnalysisJobBuilder().addTransformerChangeListener(this);

        _containerPanel = new DCPanel();
        _containerPanel.setLayout(new BoxLayout(_containerPanel, BoxLayout.X_AXIS));

        _unitPropertyWidget = createUnitPropertyWidget();

        // only facilitate horizontal scroll
        final JScrollPane scroll = new JScrollPane(_containerPanel);
        scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);

        add(scroll);

        final CoalesceUnit[] coalesceUnits =
                (CoalesceUnit[]) getComponentBuilder().getConfiguredProperty(_unitProperty);

        refresh(coalesceUnits);

        if (coalesceUnits != null) {
            // Call fireValueChanged() to provoke the check for non-used
            // streams. This cleans up the InputColumn[] property of streams
            // that are not relevant at all. Another way to think of it is that
            // irrelevant lines on the graph behind will be removed.
            fireValueChanged();
        }
    }

    private void refresh(final CoalesceUnit[] units) {
        _tablePanels.clear();
        _containerPanel.removeAll();

        final AnalysisJobBuilder ajb = getAnalysisJobBuilder();

        final InputColumn[] inputColumns = ajb.getSourceColumns().toArray(new InputColumn[0]);

        // TODO: We need a SourceColumnFinder that is aware of also nested jobs
        final SourceColumnFinder sourceColumnFinder = new SourceColumnFinder();
        sourceColumnFinder.addSources(ajb);

        // build registries of available columns and coalesced columns
        final Multimap> allTablesAndColumns = ArrayListMultimap.create();
        final Multimap> coalescedTablesAndColumns = ArrayListMultimap.create();

        for (final InputColumn inputColumn : inputColumns) {
            final Table table = sourceColumnFinder.findOriginatingTable(inputColumn);
            allTablesAndColumns.put(table, inputColumn);
        }

        if (units != null) {
            final List survivingCoalesceUnits = new ArrayList<>(units.length);
            for (CoalesceUnit unit : units) {
                // Not necessarily initialized yet, so no _initializedUnits available
                final InputColumn[] updatedInputColumns = unit.getUpdatedInputColumns(inputColumns, false);

                if (updatedInputColumns.length > 0) {
                    unit = unit.getUpdatedCoalesceUnit(updatedInputColumns);
                    survivingCoalesceUnits.add(unit);
                    for (final InputColumn inputColumn : updatedInputColumns) {
                        final Table originatingTable = sourceColumnFinder.findOriginatingTable(inputColumn);
                        coalescedTablesAndColumns.put(originatingTable, inputColumn);
                    }
                }
            }
            if (!Arrays
                    .equals(units, survivingCoalesceUnits.toArray(new CoalesceUnit[survivingCoalesceUnits.size()]))) {
                final Map properties = new HashMap<>();
                properties.put(getPropertyDescriptor(), getValue());
                properties.put(_unitProperty,
                        survivingCoalesceUnits.toArray(new CoalesceUnit[survivingCoalesceUnits.size()]));
                fireValuesChanged(properties);
            }
        }

        for (final Table table : allTablesAndColumns.keySet()) {
            final StreamColumnListPanel tablePanel = new StreamColumnListPanel(ajb, table, panel -> {
                fireValueChanged();
                _unitPropertyWidget.fireValueChanged();
            });

            final Collection> selectedColumns = coalescedTablesAndColumns.get(table);

            for (final InputColumn inputColumn : selectedColumns) {
                tablePanel.addInputColumn(inputColumn, true);
            }

            final Collection> columns = new ArrayList<>(allTablesAndColumns.get(table));
            columns.removeAll(selectedColumns);
            for (final InputColumn inputColumn : columns) {
                tablePanel.addInputColumn(inputColumn, false);
            }

            tablePanel.refresh();

            _tablePanels.add(tablePanel);
            _containerPanel.add(tablePanel);
        }
    }

    @Override
    public void onPanelRemove() {
        super.onPanelRemove();
        getAnalysisJobBuilder().removeTransformerChangeListener(this);
    }

    public PropertyWidget getUnitPropertyWidget() {
        return _unitPropertyWidget;
    }

    private MinimalPropertyWidget createUnitPropertyWidget() {
        return new MinimalPropertyWidget(getComponentBuilder(), _unitProperty) {

            @Override
            public JComponent getWidget() {
                // do not return a visual widget
                return null;
            }

            @Override
            public CoalesceUnit[] getValue() {
                final CoalesceUnit[] units = getCoalesceUnits();
                if (units.length == 0) {
                    logger.debug("Returning Units.value = null");
                    return null;
                }
                if (logger.isDebugEnabled()) {
                    logger.debug("Returning Units.value = {}", Arrays.toString(units));
                }
                return units;
            }

            @Override
            protected void setValue(final CoalesceUnit[] value) {
            }

            @Override
            public boolean isSet() {
                return StreamColumnMatrixMultipleCoalesceUnitPropertyWidget.this.isSet();
            }
        };
    }

    protected CoalesceUnit[] getCoalesceUnits() {
        int max = 0;

        final List>> allCoalescedInputColumns = new ArrayList<>();
        for (final StreamColumnListPanel tablePanel : _tablePanels) {
            final List> coalescedInputColumns = tablePanel.getCoalescedInputColumns();
            allCoalescedInputColumns.add(coalescedInputColumns);
            max = Math.max(max, coalescedInputColumns.size());
        }

        final CoalesceUnit[] result = new CoalesceUnit[max];
        for (int i = 0; i < result.length; i++) {
            final List> coalesceUnitInputColumns = new ArrayList<>();
            for (final List> coalescedInputColumnsForTable : allCoalescedInputColumns) {
                if (coalescedInputColumnsForTable.size() - 1 >= i) {
                    coalesceUnitInputColumns.add(coalescedInputColumnsForTable.get(i));
                }
            }
            final CoalesceUnit unit = new CoalesceUnit(coalesceUnitInputColumns);
            result[i] = unit;
        }
        return result;
    }

    @Override
    public InputColumn[] getValue() {
        final List> result = new ArrayList<>();
        for (final StreamColumnListPanel tablePanel : _tablePanels) {
            if (tablePanel.hasSelectedInputColumns()) {
                result.addAll(tablePanel.getAllInputColumns());
            }
        }
        return result.toArray(new InputColumn[result.size()]);
    }

    @Override
    protected void setValue(final InputColumn[] value) {
    }

    @Override
    public void onNameChanged(final MutableInputColumn inputColumn, final String oldName, final String newName) {
    }

    @Override
    public void onVisibilityChanged(final MutableInputColumn inputColumn, final boolean hidden) {
    }

    @Override
    public void onOutputChanged(final TransformerComponentBuilder transformerJobBuilder,
            final List> outputColumns) {
        if (transformerJobBuilder != getComponentBuilder()) {
            refresh(getCoalesceUnits());
        }
    }

    @Override
    public void onAdd(final TransformerComponentBuilder builder) {
    }

    @Override
    public void onConfigurationChanged(final TransformerComponentBuilder builder) {
    }

    @Override
    public void onRequirementChanged(final TransformerComponentBuilder builder) {
    }

    @Override
    public void onRemove(final TransformerComponentBuilder componentBuilder) {
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy