org.datacleaner.widgets.ExecuteButtonOptions Maven / Gradle / Ivy
/**
* DataCleaner (community edition)
* 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.datacleaner.widgets;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.metamodel.util.Action;
import org.datacleaner.configuration.DataCleanerConfiguration;
import org.datacleaner.configuration.DataCleanerConfigurationImpl;
import org.datacleaner.configuration.DataCleanerEnvironmentImpl;
import org.datacleaner.job.AnalysisJob;
import org.datacleaner.job.builder.AnalysisJobBuilder;
import org.datacleaner.job.builder.AnalyzerComponentBuilder;
import org.datacleaner.job.builder.ComponentBuilder;
import org.datacleaner.job.concurrent.SingleThreadedTaskRunner;
import org.datacleaner.util.IconUtils;
import org.datacleaner.util.PreviewUtils;
import org.datacleaner.util.SourceColumnFinder;
import org.datacleaner.util.WidgetFactory;
import org.datacleaner.util.WidgetUtils;
import org.datacleaner.windows.AnalysisJobBuilderWindow;
/**
* This class provides an API for hooking in "Execute" button options.
*
* Each hook is represented as an {@link ExecutionMenuItem} that will be shown
* when the user clicks the caret symbol next to the "Execute" button.
*/
public class ExecuteButtonOptions {
public interface ExecutionMenuItem {
String getText();
String getIconPath();
/**
* Creates the action listener for the menu item. This method will be
* called each time the menu is popping up.
*
* If the method returns null then the menu item will be marked as
* disabled. This may be useful if certain functionality doesn't always
* apply to the given job.
*
* @param analysisJobBuilder
* the current job builder object
* @param executeAction
* an {@link Action} that can be invoked with any job builder
* to execute it.
* @return
*/
ActionListener createActionListener(AnalysisJobBuilder analysisJobBuilder,
Action executeAction, AnalysisJobBuilderWindow analysisJobBuilderWindow);
}
private abstract static class SimpleExecutionMenuItem implements ExecutionMenuItem {
private final String _text;
private final String _iconPath;
public SimpleExecutionMenuItem(final String text, final String iconPath) {
_text = text;
_iconPath = iconPath;
}
@Override
public final String getIconPath() {
return _iconPath;
}
@Override
public final String getText() {
return _text;
}
@Override
public final ActionListener createActionListener(final AnalysisJobBuilder analysisJobBuilder,
final Action executeAction,
final AnalysisJobBuilderWindow analysisJobBuilderWindow) {
return event -> {
try {
run(analysisJobBuilder, executeAction, analysisJobBuilderWindow);
} catch (final Exception e) {
WidgetUtils.showErrorMessage("Unexpected error",
"An error occurred while executing job in mode '" + getText() + "'", e);
}
};
}
protected abstract void run(AnalysisJobBuilder analysisJobBuilder, Action executeAction,
AnalysisJobBuilderWindow analysisJobBuilderWindow) throws Exception;
}
/**
* Special purpose {@link ExecutionMenuItem} that represent a separator in
* the menu.
*/
public static class Separator implements ExecutionMenuItem {
@Override
public String getText() {
return null;
}
@Override
public String getIconPath() {
return null;
}
@Override
public ActionListener createActionListener(final AnalysisJobBuilder analysisJobBuilder,
final Action executeAction,
final AnalysisJobBuilderWindow analysisJobBuilderWindow) {
return null;
}
}
private static final List MENU_ITEMS = new ArrayList<>();
static {
// initialize the default menu items
addMenuItem(new SimpleExecutionMenuItem("Run normally", IconUtils.ACTION_EXECUTE) {
@Override
protected void run(final AnalysisJobBuilder analysisJobBuilder,
final Action executeAction,
final AnalysisJobBuilderWindow analysisJobBuilderWindow) throws Exception {
executeAction.run(analysisJobBuilder);
}
});
addMenuItem(new SimpleExecutionMenuItem("Run first N records", IconUtils.ACTION_PREVIEW) {
@Override
protected void run(final AnalysisJobBuilder analysisJobBuilder,
final Action executeAction,
final AnalysisJobBuilderWindow analysisJobBuilderWindow) throws Exception {
final Integer maxRows = WidgetFactory.showMaxRowsDialog(100);
if (maxRows != null) {
final AnalysisJob jobCopy = analysisJobBuilder.toAnalysisJob(false);
final AnalysisJobBuilder jobBuilderCopy =
new AnalysisJobBuilder(analysisJobBuilder.getConfiguration(), jobCopy);
final Set analyzers = jobBuilderCopy.getComponentBuilders().stream()
.filter(o -> o instanceof AnalyzerComponentBuilder).collect(Collectors.toSet());
final SourceColumnFinder scf = new SourceColumnFinder();
scf.addSources(jobBuilderCopy);
final Set filtered =
analyzers.stream().filter(acb -> PreviewUtils.hasFilterPresent(scf, acb))
.collect(Collectors.toSet());
if (filtered.size() == 0) {
PreviewUtils.limitJobRows(jobBuilderCopy, jobBuilderCopy.getComponentBuilders(), maxRows);
} else {
PreviewUtils.limitJobRows(jobBuilderCopy, jobBuilderCopy.getFilterComponentBuilders(), maxRows);
final Set unfilteredAnalyzers =
analyzers.stream().filter(acb -> !PreviewUtils.hasFilterPresent(scf, acb))
.collect(Collectors.toSet());
// TODO: This may risk running through more input rows than intended, but alternative is worse.
// TODO: Transformers implementing HasAnalyzerResult will _not_ undergo special filtering.
PreviewUtils.limitJobRows(jobBuilderCopy, unfilteredAnalyzers, maxRows);
}
executeAction.run(jobBuilderCopy);
}
}
});
addMenuItem(new SimpleExecutionMenuItem("Run single-threaded", IconUtils.MODEL_ROW) {
@Override
protected void run(final AnalysisJobBuilder analysisJobBuilder,
final Action executeAction,
final AnalysisJobBuilderWindow analysisJobBuilderWindow) throws Exception {
final DataCleanerConfiguration baseConfiguration = analysisJobBuilder.getConfiguration();
final DataCleanerConfigurationImpl configuration = new DataCleanerConfigurationImpl(baseConfiguration)
.withEnvironment(new DataCleanerEnvironmentImpl(baseConfiguration.getEnvironment())
.withTaskRunner(new SingleThreadedTaskRunner()));
final AnalysisJob jobCopy = analysisJobBuilder.toAnalysisJob(false);
final AnalysisJobBuilder jobBuilderCopy = new AnalysisJobBuilder(configuration, jobCopy);
executeAction.run(jobBuilderCopy);
}
});
}
private ExecuteButtonOptions() {
// prevent instantiation
}
public static void addMenuItem(final ExecutionMenuItem menuItem) {
MENU_ITEMS.add(menuItem);
}
public static void addMenuItem(final int index, final ExecutionMenuItem menuItem) {
MENU_ITEMS.add(index, menuItem);
}
public static void removeMenuItem(final ExecutionMenuItem menuItem) {
MENU_ITEMS.remove(menuItem);
}
public static void removeMenuItem(final int index) {
MENU_ITEMS.remove(index);
}
public static List getMenuItems() {
return Collections.unmodifiableList(MENU_ITEMS);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy