/**
* 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.operator.meta;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import com.rapidminer.operator.ExecutionUnit;
import com.rapidminer.operator.OperatorChain;
import com.rapidminer.operator.OperatorDescription;
import com.rapidminer.operator.OperatorException;
import com.rapidminer.operator.Value;
import com.rapidminer.operator.ports.InputPorts;
import com.rapidminer.operator.ports.MultiInputPortPairExtender;
import com.rapidminer.operator.ports.MultiOutputPortPairExtender;
import com.rapidminer.operator.ports.OutputPorts;
import com.rapidminer.operator.ports.Port;
import com.rapidminer.operator.ports.metadata.SubprocessTransformRule;
import com.rapidminer.parameter.ParameterType;
import com.rapidminer.parameter.ParameterTypeString;
import com.rapidminer.tools.LogService;
/**
* <p>
* This operator performs the inner operators and delivers the result of the inner operators. If any
* error occurs during this subprocess, this error will be neglected and this operator simply will
* return no additional input.
* </p>
*
* <p>
* Please use this operator with care since it will also cover errors which are not expected by the
* analyst. In combination with a process branch, however, it can be used to handle exceptions in
* the analysis process (i.e. expected errors).
* </p>
*
* @author Ingo Mierswa, Marius Helf
*/
public class ExceptionHandling extends OperatorChain {
public static final String PARAMETER_EXCEPTION_MACRO = "exception_macro";
private boolean withoutError = true;
private Throwable throwable;
private static final int TRY_SUBPROCESS = 0;
private static final int CATCH_SUBPROCESS = 1;
private final MultiOutputPortPairExtender inputExtender = new MultiOutputPortPairExtender("in", getInputPorts(),
new OutputPorts[] { getSubprocess(0).getInnerSources(), getSubprocess(1).getInnerSources() });
private final MultiInputPortPairExtender outputExtender = new MultiInputPortPairExtender("out", getOutputPorts(),
new InputPorts[] { getSubprocess(0).getInnerSinks(), getSubprocess(1).getInnerSinks() });
public ExceptionHandling(OperatorDescription description) {
super(description, "Try", "Catch");
inputExtender.start();
getTransformer().addRule(inputExtender.makePassThroughRule());
getTransformer().addRule(new SubprocessTransformRule(getSubprocess(0)));
getTransformer().addRule(new SubprocessTransformRule(getSubprocess(1)));
getTransformer().addRule(outputExtender.makePassThroughRule());
outputExtender.start();
addValue(new Value("success", "Indicates whether the execution was successful") {
@Override
public Object getValue() {
return withoutError;
}
@Override
public boolean isNominal() {
return true;
}
});
addValue(new Value("exception", "The exception that occured during execution.") {
@Override
public Object getValue() {
return throwable;
}
@Override
public boolean isNominal() {
return true;
}
});
}
@Override
public void doWork() throws OperatorException {
withoutError = true;
throwable = null;
ExecutionUnit tryProcess = getSubprocess(TRY_SUBPROCESS);
ExecutionUnit catchProcess = getSubprocess(CATCH_SUBPROCESS);
tryProcess.getInnerSinks().clear(Port.CLEAR_DATA);
catchProcess.getInnerSinks().clear(Port.CLEAR_DATA);
try {
inputExtender.passDataThrough(TRY_SUBPROCESS);
tryProcess.execute();
outputExtender.passDataThrough(TRY_SUBPROCESS);
} catch (Throwable e) {
LogService.getRoot().log(Level.WARNING,
"Error occurred and will be neglected by " + getName() + ": " + e.getMessage(), e);
if (isParameterSet(PARAMETER_EXCEPTION_MACRO)) {
getProcess().getMacroHandler().addMacro(getParameterAsString(PARAMETER_EXCEPTION_MACRO), e.getMessage());
}
withoutError = false;
this.throwable = e;
inputExtender.passDataThrough(CATCH_SUBPROCESS);
catchProcess.execute();
outputExtender.passDataThrough(CATCH_SUBPROCESS);
}
}
@Override
public List<ParameterType> getParameterTypes() {
List<ParameterType> types = new LinkedList<ParameterType>();
types.add(new ParameterTypeString(PARAMETER_EXCEPTION_MACRO,
"The name of the macro a potentially occuring exception message will be stored in.", true));
types.addAll(super.getParameterTypes());
return types;
}
}