/** * Copyright (C) 2001-2017 by RapidMiner and the contributors * * Complete list of developers available at our web site: * * http://rapidminer.com * * This program is free software: you can redistribute it and/or modify it under the terms of the * GNU Affero General Public License as published by the Free Software Foundation, either version 3 * of the License, or (at your option) any later version. * * 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 * Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License along with this program. * If not, see http://www.gnu.org/licenses/. */ package com.rapidminer.gui; import java.util.List; import java.util.logging.Level; import com.rapidminer.NoBugError; import com.rapidminer.Process; import com.rapidminer.RapidMiner; import com.rapidminer.core.license.DatabaseConstraintViolationException; import com.rapidminer.core.license.LicenseViolationException; import com.rapidminer.gui.tools.ProcessGUITools; import com.rapidminer.gui.tools.SwingTools; import com.rapidminer.operator.IOContainer; import com.rapidminer.operator.Operator; import com.rapidminer.operator.OperatorException; import com.rapidminer.operator.ProcessStoppedException; import com.rapidminer.operator.UserError; import com.rapidminer.parameter.UndefinedParameterError; import com.rapidminer.tools.LogService; import com.rapidminer.tools.ParameterService; import com.rapidminer.tools.SystemInfoUtilities; import com.rapidminer.tools.Tools; import com.rapidminer.tools.usagestats.ActionStatisticsCollector; /** * A Thread for running an process in the RapidMinerGUI. This thread is necessary in order to keep * the GUI running (and working). Please note that this class can only be used from a running * RapidMiner GUI since several dependencies to the class {@link RapidMinerGUI} and * {@link MainFrame} exist. If you want to perform an process in its own thread from your own * program simply use a Java Thread peforming the method process.run() in its run()-method. * * @author Ingo Mierswa, Simon Fischer */ public class ProcessThread extends Thread { private Process process; public ProcessThread(final Process process) { super("ProcessThread"); this.process = process; } @Override public void run() { try { IOContainer results = process.run(); beep("success"); process.getRootOperator().sendEmail(results, null); RapidMinerGUI.getMainFrame().processEnded(process, results); } catch (DatabaseConstraintViolationException ex) { // Check DatabaseConstraintViolationException first as it is a subclass of // the more general LicenseViolationException if (ex.getOperatorName() != null) { LogService.getRoot().log(Level.SEVERE, "com.rapidminer.gui.ProcessThread.database_constraint_violation_exception_in_operator", new Object[] { ex.getDatabaseURL(), ex.getOperatorName() }); } else { LogService.getRoot().log(Level.SEVERE, "com.rapidminer.gui.ProcessThread.database_constraint_violation_exception", new Object[] { ex.getDatabaseURL() }); } } catch (LicenseViolationException ex) { LogService.getRoot().log(Level.SEVERE, "com.rapidminer.gui.ProcessThread.operator_constraint_violation_exception", new Object[] { ex.getOperatorName() }); } catch (ProcessStoppedException ex) { process.getLogger().info(ex.getMessage()); // here the process ended method is not called ! let the thread finish the // current operator and send no events to the main frame... // also no beep... } catch (Throwable e) { if (!(e instanceof OperatorException)) { // otherwise it was already counted ActionStatisticsCollector.getInstance().log(process.getCurrentOperator(), ActionStatisticsCollector.OPERATOR_EVENT_FAILURE); ActionStatisticsCollector.getInstance().log(process.getCurrentOperator(), ActionStatisticsCollector.OPERATOR_EVENT_RUNTIME_EXCEPTION); } beep("error"); String debugProperty = ParameterService.getParameterValue(RapidMiner.PROPERTY_RAPIDMINER_GENERAL_DEBUGMODE); boolean debugMode = Tools.booleanValue(debugProperty, false); String message = e.getMessage(); if (!debugMode) { if (e instanceof RuntimeException) { if (e.getMessage() != null) { message = "operator cannot be executed (" + e.getMessage() + "). Check the log messages..."; } else { message = "operator cannot be executed. Check the log messages..."; } } } process.getLogger().log(Level.SEVERE, "Process failed: " + message, e); logProcessTreeList(10, "==>", process.getCurrentOperator()); try { process.getRootOperator().sendEmail(null, e); } catch (UndefinedParameterError ex) { // cannot happen process.getLogger().log(Level.WARNING, "Problems during sending result mail: " + ex.getMessage(), ex); } if (e instanceof OutOfMemoryError) { // out of memory, give memory hint SwingTools.showVerySimpleErrorMessage("proc_failed_out_of_mem"); ActionStatisticsCollector.getInstance().log(ActionStatisticsCollector.TYPE_ERROR, "out_of_memory", String.valueOf(SystemInfoUtilities.getMaxHeapMemorySize())); } else if (e instanceof NoBugError) { // no bug? Show nice error screen (user error infos) if (e instanceof UserError) { ProcessGUITools.displayBubbleForUserError((UserError) e); } else { handleError(debugMode, e, new Object[] {}); } } else { if (debugMode) { handleError(true, e, new Object[] {}); } else { // perform process check. No bug report if errors... if (e instanceof NullPointerException || e instanceof ArrayIndexOutOfBoundsException) { LogService.getRoot().log(Level.SEVERE, e.toString(), e); SwingTools.showVerySimpleErrorMessage("proc_failed_without_obv_reason"); } else { SwingTools.showSimpleErrorMessage("process_failed_simple", e, true, new Object[] {}); } } } RapidMinerGUI.getMainFrame().processEnded(this.process, null); } finally { if (process.getProcessState() != Process.PROCESS_STATE_STOPPED) { process.stop(); } this.process = null; } } private void logProcessTreeList(int indent, String mark, Operator markOperator) { process.getLogger().log(Level.SEVERE, "Here: "); List<String> processTreeList = process.getRootOperator().createProcessTreeList(indent, "", "", markOperator, mark); for (String logEntry : processTreeList) { process.getLogger().log(Level.SEVERE, logEntry); } } public static void beep(final String reason) { if (Tools.booleanValue(ParameterService.getParameterValue("rapidminer.gui.beep." + reason), false)) { java.awt.Toolkit.getDefaultToolkit().beep(); } } public void stopProcess() { if (process != null) { this.process.stop(); this.interrupt(); } } public void pauseProcess() { if (process != null) { this.process.pause(); } } @Override public String toString() { return "ProcessThread (" + process.getProcessLocation() + ")"; } /** * Displays an error dialog for {@link Throwable}s. * * @param debugMode * whether debug mode is enabled * @param t * the throwable instance * @param args * optional i18n arguments */ private void handleError(boolean debugMode, Throwable t, Object[] args) { SwingTools.showFinalErrorMessage("process_failed_simple", t, debugMode, new Object[] {}); } }