135 lines
5.1 KiB
Java
135 lines
5.1 KiB
Java
/* ====================================================================
|
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
|
contributor license agreements. See the NOTICE file distributed with
|
|
this work for additional information regarding copyright ownership.
|
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
|
(the "License"); you may not use this file except in compliance with
|
|
the License. You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
==================================================================== */
|
|
|
|
package org.apache.poi.hssf.record.formula.eval;
|
|
|
|
/**
|
|
* This class is used to simplify error handling logic <i>within</i> operator and function
|
|
* implementations. Note - <tt>OperationEval.evaluate()</tt> and <tt>Function.evaluate()</tt>
|
|
* method signatures do not throw this exception so it cannot propagate outside.<p/>
|
|
*
|
|
* Here is an example coded without <tt>EvaluationException</tt>, to show how it can help:
|
|
* <pre>
|
|
* public Eval evaluate(Eval[] args, int srcRow, short srcCol) {
|
|
* // ...
|
|
* Eval arg0 = args[0];
|
|
* if(arg0 instanceof ErrorEval) {
|
|
* return arg0;
|
|
* }
|
|
* if(!(arg0 instanceof AreaEval)) {
|
|
* return ErrorEval.VALUE_INVALID;
|
|
* }
|
|
* double temp = 0;
|
|
* AreaEval area = (AreaEval)arg0;
|
|
* ValueEval[] values = area.getValues();
|
|
* for (int i = 0; i < values.length; i++) {
|
|
* ValueEval ve = values[i];
|
|
* if(ve instanceof ErrorEval) {
|
|
* return ve;
|
|
* }
|
|
* if(!(ve instanceof NumericValueEval)) {
|
|
* return ErrorEval.VALUE_INVALID;
|
|
* }
|
|
* temp += ((NumericValueEval)ve).getNumberValue();
|
|
* }
|
|
* // ...
|
|
* }
|
|
* </pre>
|
|
* In this example, if any error is encountered while processing the arguments, an error is
|
|
* returned immediately. This code is difficult to refactor due to all the points where errors
|
|
* are returned.<br/>
|
|
* Using <tt>EvaluationException</tt> allows the error returning code to be consolidated to one
|
|
* place.<p/>
|
|
* <pre>
|
|
* public Eval evaluate(Eval[] args, int srcRow, short srcCol) {
|
|
* try {
|
|
* // ...
|
|
* AreaEval area = getAreaArg(args[0]);
|
|
* double temp = sumValues(area.getValues());
|
|
* // ...
|
|
* } catch (EvaluationException e) {
|
|
* return e.getErrorEval();
|
|
* }
|
|
*}
|
|
*
|
|
*private static AreaEval getAreaArg(Eval arg0) throws EvaluationException {
|
|
* if (arg0 instanceof ErrorEval) {
|
|
* throw new EvaluationException((ErrorEval) arg0);
|
|
* }
|
|
* if (arg0 instanceof AreaEval) {
|
|
* return (AreaEval) arg0;
|
|
* }
|
|
* throw EvaluationException.invalidValue();
|
|
*}
|
|
*
|
|
*private double sumValues(ValueEval[] values) throws EvaluationException {
|
|
* double temp = 0;
|
|
* for (int i = 0; i < values.length; i++) {
|
|
* ValueEval ve = values[i];
|
|
* if (ve instanceof ErrorEval) {
|
|
* throw new EvaluationException((ErrorEval) ve);
|
|
* }
|
|
* if (!(ve instanceof NumericValueEval)) {
|
|
* throw EvaluationException.invalidValue();
|
|
* }
|
|
* temp += ((NumericValueEval) ve).getNumberValue();
|
|
* }
|
|
* return temp;
|
|
*}
|
|
* </pre>
|
|
* It is not mandatory to use EvaluationException, doing so might give the following advantages:<br/>
|
|
* - Methods can more easily be extracted, allowing for re-use.<br/>
|
|
* - Type management (typecasting etc) is simpler because error conditions have been separated from
|
|
* intermediate calculation values.<br/>
|
|
* - Fewer local variables are required. Local variables can have stronger types.<br/>
|
|
* - It is easier to mimic common Excel error handling behaviour (exit upon encountering first
|
|
* error), because exceptions conveniently propagate up the call stack regardless of execution
|
|
* points or the number of levels of nested calls.<p/>
|
|
*
|
|
* <b>Note</b> - Only standard evaluation errors are represented by <tt>EvaluationException</tt> (
|
|
* i.e. conditions expected to be encountered when evaluating arbitrary Excel formulas). Conditions
|
|
* that could never occur in an Excel spreadsheet should result in runtime exceptions. Care should
|
|
* be taken to not translate any POI internal error into an Excel evaluation error code.
|
|
*
|
|
* @author Josh Micich
|
|
*/
|
|
public final class EvaluationException extends Exception {
|
|
private final ErrorEval _errorEval;
|
|
|
|
public EvaluationException(ErrorEval errorEval) {
|
|
_errorEval = errorEval;
|
|
}
|
|
// some convenience factory methods
|
|
|
|
/** <b>#VALUE!</b> - Wrong type of operand */
|
|
public static EvaluationException invalidValue() {
|
|
return new EvaluationException(ErrorEval.VALUE_INVALID);
|
|
}
|
|
/** <b>#REF!</b> - Illegal or deleted cell reference */
|
|
public static EvaluationException invalidRef() {
|
|
return new EvaluationException(ErrorEval.REF_INVALID);
|
|
}
|
|
/** <b>#NUM!</b> - Value range overflow */
|
|
public static EvaluationException numberError() {
|
|
return new EvaluationException(ErrorEval.NUM_ERROR);
|
|
}
|
|
|
|
public ErrorEval getErrorEval() {
|
|
return _errorEval;
|
|
}
|
|
}
|