aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJosh Micich <josh@apache.org>2009-09-17 00:00:57 +0000
committerJosh Micich <josh@apache.org>2009-09-17 00:00:57 +0000
commit30dcd662576e1fbbf52a6551c149582de2f1fef9 (patch)
tree05e02da2ec8e47921ea051f3d3ec75c96036ea28 /src
parenta82e264754e5a6e74968ab1032892283764538f3 (diff)
downloadpoi-30dcd662576e1fbbf52a6551c149582de2f1fef9.tar.gz
poi-30dcd662576e1fbbf52a6551c149582de2f1fef9.zip
Improvements to patch 47809 (support for UDFs)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@816016 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src')
-rw-r--r--src/java/org/apache/poi/hssf/record/NameRecord.java32
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/atp/AnalysisToolPak.java32
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/eval/UserDefinedFunction.java51
-rwxr-xr-xsrc/java/org/apache/poi/hssf/record/formula/toolpack/MainToolPacksHandler.java102
-rwxr-xr-xsrc/java/org/apache/poi/hssf/record/formula/udf/AggregatingUDFFinder.java52
-rwxr-xr-xsrc/java/org/apache/poi/hssf/record/formula/udf/DefaultUDFFinder.java (renamed from src/java/org/apache/poi/hssf/record/formula/toolpack/DefaultToolPack.java)46
-rwxr-xr-xsrc/java/org/apache/poi/hssf/record/formula/udf/UDFFinder.java (renamed from src/java/org/apache/poi/hssf/record/formula/toolpack/ToolPack.java)36
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java267
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java21
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java32
-rw-r--r--src/java/org/apache/poi/ss/formula/EvaluationWorkbook.java14
-rw-r--r--src/java/org/apache/poi/ss/formula/OperationEvaluationContext.java5
-rw-r--r--src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java16
-rw-r--r--src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationWorkbook.java6
-rw-r--r--src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluator.java16
-rw-r--r--src/java/org/apache/poi/ss/usermodel/Name.java8
-rw-r--r--src/java/org/apache/poi/ss/usermodel/Workbook.java32
-rw-r--r--src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationWorkbook.java7
-rw-r--r--src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFFormulaEvaluator.java23
-rw-r--r--src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java26
-rw-r--r--src/testcases/org/apache/poi/hssf/record/formula/eval/TestExternalFunction.java136
-rw-r--r--src/testcases/org/apache/poi/ss/formula/TestWorkbookEvaluator.java2
-rw-r--r--src/testcases/org/apache/poi/ss/formula/WorkbookEvaluatorTestHelper.java6
23 files changed, 392 insertions, 576 deletions
diff --git a/src/java/org/apache/poi/hssf/record/NameRecord.java b/src/java/org/apache/poi/hssf/record/NameRecord.java
index 6b38e36d4e..9084f12369 100644
--- a/src/java/org/apache/poi/hssf/record/NameRecord.java
+++ b/src/java/org/apache/poi/hssf/record/NameRecord.java
@@ -33,9 +33,7 @@ import org.apache.poi.util.StringUtil;
* @author Libin Roman (Vista Portal LDT. Developer)
* @author Sergei Kozello (sergeikozello at mail.ru)
* @author Glen Stampoultzis (glens at apache.org)
- * @version 1.0-pre
- *
- * Modified 8/31/09 by Petr Udalau - added method setFunction(boolean)
+ * @author Petr Udalau - added method setFunction(boolean)
*/
public final class NameRecord extends StandardRecord {
public final static short sid = 0x0018;
@@ -135,7 +133,7 @@ public final class NameRecord extends StandardRecord {
/**
* For named ranges, and built-in names
- * @return the 1-based sheet number.
+ * @return the 1-based sheet number.
*/
public int getSheetNumber()
{
@@ -239,13 +237,13 @@ public final class NameRecord extends StandardRecord {
public boolean isFunctionName() {
return (field_1_option_flag & Option.OPT_FUNCTION_NAME) != 0;
}
-
- /**
- * Indicates that the defined name refers to a user-defined function.
- * This attribute is used when there is an add-in or other code project associated with the file.
- *
- * @param value <code>true</code> indicates the name refers to a function.
- */
+
+ /**
+ * Indicates that the defined name refers to a user-defined function.
+ * This attribute is used when there is an add-in or other code project associated with the file.
+ *
+ * @param value <code>true</code> indicates the name refers to a function.
+ */
public void setFunction(boolean function){
if (function) {
field_1_option_flag |= Option.OPT_FUNCTION_NAME;
@@ -351,7 +349,7 @@ public final class NameRecord extends StandardRecord {
int field_8_length_description_text = field_15_description_text.length();
int field_9_length_help_topic_text = field_16_help_topic_text.length();
int field_10_length_status_bar_text = field_17_status_bar_text.length();
-
+
// size defined below
out.writeShort(getOptionFlag());
out.writeByte(getKeyboardShortcut());
@@ -379,7 +377,7 @@ public final class NameRecord extends StandardRecord {
}
field_13_name_definition.serializeTokens(out);
field_13_name_definition.serializeArrayConstantData(out);
-
+
StringUtil.putCompressedUnicode( getCustomMenuText(), out);
StringUtil.putCompressedUnicode( getDescriptionText(), out);
StringUtil.putCompressedUnicode( getHelpTopicText(), out);
@@ -388,14 +386,14 @@ public final class NameRecord extends StandardRecord {
private int getNameRawSize() {
if (isBuiltInName()) {
return 1;
- }
+ }
int nChars = field_12_name_text.length();
if(field_11_nameIsMultibyte) {
return 2 * nChars;
- }
+ }
return nChars;
}
-
+
protected int getDataSize() {
return 13 // 3 shorts + 7 bytes
+ getNameRawSize()
@@ -456,7 +454,7 @@ public final class NameRecord extends StandardRecord {
}
}
- int nBytesAvailable = in.available() - (f7_customMenuLen
+ int nBytesAvailable = in.available() - (f7_customMenuLen
+ f8_descriptionTextLen + f9_helpTopicTextLen + f10_statusBarTextLen);
field_13_name_definition = Formula.read(field_4_length_name_definition, in, nBytesAvailable);
diff --git a/src/java/org/apache/poi/hssf/record/formula/atp/AnalysisToolPak.java b/src/java/org/apache/poi/hssf/record/formula/atp/AnalysisToolPak.java
index acfb306242..61f108b674 100644
--- a/src/java/org/apache/poi/hssf/record/formula/atp/AnalysisToolPak.java
+++ b/src/java/org/apache/poi/hssf/record/formula/atp/AnalysisToolPak.java
@@ -22,14 +22,17 @@ import java.util.Map;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
import org.apache.poi.hssf.record.formula.functions.FreeRefFunction;
-import org.apache.poi.hssf.record.formula.toolpack.ToolPack;
+import org.apache.poi.hssf.record.formula.udf.UDFFinder;
import org.apache.poi.ss.formula.OperationEvaluationContext;
import org.apache.poi.ss.formula.eval.NotImplementedException;
/**
- * Modified 09/07/09 by Petr Udalau - systematized work of ToolPacks.
+ * @author Josh Micich
+ * @author Petr Udalau - systematized work of add-in libraries and user defined functions.
*/
-public final class AnalysisToolPak implements ToolPack {
+public final class AnalysisToolPak implements UDFFinder {
+
+ public static final UDFFinder instance = new AnalysisToolPak();
private static final class NotImplemented implements FreeRefFunction {
private final String _functionName;
@@ -42,13 +45,18 @@ public final class AnalysisToolPak implements ToolPack {
throw new NotImplementedException(_functionName);
}
};
-
- private Map<String, FreeRefFunction> _functionsByName = createFunctionsMap();
+
+ private final Map<String, FreeRefFunction> _functionsByName = createFunctionsMap();
+
+
+ private AnalysisToolPak() {
+ // enforce singleton
+ }
public FreeRefFunction findFunction(String name) {
return _functionsByName.get(name);
}
-
+
private Map<String, FreeRefFunction> createFunctionsMap() {
Map<String, FreeRefFunction> m = new HashMap<String, FreeRefFunction>(100);
@@ -153,16 +161,4 @@ public final class AnalysisToolPak implements ToolPack {
FreeRefFunction func = pFunc == null ? new NotImplemented(functionName) : pFunc;
m.put(functionName, func);
}
-
- public void addFunction(String name, FreeRefFunction evaluator) {
- r(_functionsByName, name, evaluator);
- }
-
- public boolean containsFunction(String name) {
- return _functionsByName.containsKey(name);
- }
-
- public void removeFunction(String name) {
- _functionsByName.remove(name);
- }
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/UserDefinedFunction.java b/src/java/org/apache/poi/hssf/record/formula/eval/UserDefinedFunction.java
index bf390141ee..223f13378e 100644
--- a/src/java/org/apache/poi/hssf/record/formula/eval/UserDefinedFunction.java
+++ b/src/java/org/apache/poi/hssf/record/formula/eval/UserDefinedFunction.java
@@ -18,8 +18,6 @@
package org.apache.poi.hssf.record.formula.eval;
import org.apache.poi.hssf.record.formula.functions.FreeRefFunction;
-import org.apache.poi.hssf.record.formula.toolpack.MainToolPacksHandler;
-import org.apache.poi.ss.formula.EvaluationWorkbook;
import org.apache.poi.ss.formula.OperationEvaluationContext;
import org.apache.poi.ss.formula.eval.NotImplementedException;
/**
@@ -28,8 +26,7 @@ import org.apache.poi.ss.formula.eval.NotImplementedException;
* <tt>AbstractFunctionPtg.field_2_fnc_index</tt> == 255)
*
* @author Josh Micich
- *
- * Modified 09/07/09 by Petr Udalau - Improved resolving of UDFs through the ToolPacks.
+ * @author Petr Udalau - Improved resolving of UDFs through the ToolPacks.
*/
final class UserDefinedFunction implements FreeRefFunction {
@@ -40,60 +37,28 @@ final class UserDefinedFunction implements FreeRefFunction {
}
public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) {
- EvaluationWorkbook workbook = ec.getWorkbook();
int nIncomingArgs = args.length;
if(nIncomingArgs < 1) {
throw new RuntimeException("function name argument missing");
}
ValueEval nameArg = args[0];
- FreeRefFunction targetFunc;
+ String functionName;
if (nameArg instanceof NameEval) {
- targetFunc = findInternalUserDefinedFunction(workbook, (NameEval) nameArg);
+ functionName = ((NameEval) nameArg).getFunctionName();
} else if (nameArg instanceof NameXEval) {
- targetFunc = findExternalUserDefinedFunction(workbook, (NameXEval) nameArg);
+ functionName = ec.getWorkbook().resolveNameXText(((NameXEval) nameArg).getPtg());
} else {
throw new RuntimeException("First argument should be a NameEval, but got ("
+ nameArg.getClass().getName() + ")");
}
+ FreeRefFunction targetFunc = ec.findUserDefinedFunction(functionName);
+ if (targetFunc == null) {
+ throw new NotImplementedException(functionName);
+ }
int nOutGoingArgs = nIncomingArgs -1;
ValueEval[] outGoingArgs = new ValueEval[nOutGoingArgs];
System.arraycopy(args, 1, outGoingArgs, 0, nOutGoingArgs);
return targetFunc.evaluate(outGoingArgs, ec);
}
-
- private static FreeRefFunction findExternalUserDefinedFunction(EvaluationWorkbook workbook,
- NameXEval n) {
- String functionName = workbook.resolveNameXText(n.getPtg());
-
- if(false) {
- System.out.println("received call to external user defined function (" + functionName + ")");
- }
- // currently only looking for functions from the 'Analysis TookPak'(contained in MainToolPacksHandler) e.g. "YEARFRAC" or "ISEVEN"
- // not sure how much this logic would need to change to support other or multiple add-ins.
- FreeRefFunction result = MainToolPacksHandler.instance().findFunction(functionName);
- if (result != null) {
- return result;
- }
- throw new NotImplementedException(functionName);
- }
-
- private static FreeRefFunction findInternalUserDefinedFunction(EvaluationWorkbook workbook,
- NameEval functionNameEval) {
-
- String functionName = functionNameEval.getFunctionName();
- if(false) {
- System.out.println("received call to internal user defined function (" + functionName + ")");
- }
- FreeRefFunction functionEvaluator = workbook.findUserDefinedFunction(functionName);
- if (functionEvaluator == null) {
- functionEvaluator = MainToolPacksHandler.instance().findFunction(functionName);
- }
- if (functionEvaluator != null) {
- return functionEvaluator;
- }
- // TODO find the implementation for the user defined function
-
- throw new NotImplementedException(functionName);
- }
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/toolpack/MainToolPacksHandler.java b/src/java/org/apache/poi/hssf/record/formula/toolpack/MainToolPacksHandler.java
deleted file mode 100755
index 9bb0c07888..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/toolpack/MainToolPacksHandler.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/* ====================================================================
- 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.toolpack;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.poi.hssf.record.formula.atp.AnalysisToolPak;
-import org.apache.poi.hssf.record.formula.functions.FreeRefFunction;
-
-/**
- * Contains all tool packs. Processing of UDF is through this class.
- *
- * @author PUdalau
- */
-public class MainToolPacksHandler{
-
- private DefaultToolPack defaultToolPack;
-
- private List<ToolPack> usedToolPacks = new ArrayList<ToolPack>();
-
- private static MainToolPacksHandler instance;
-
- /**
- * @return Unique instance of handler.
- */
- public static MainToolPacksHandler instance() {
- if (instance == null) {
- instance = new MainToolPacksHandler();
- }
- return instance;
- }
-
- /**
- * @return Default tool pack(which is obligatory exists in handler).
- */
- public DefaultToolPack getDefaultToolPack() {
- return defaultToolPack;
- }
-
- private MainToolPacksHandler() {
- defaultToolPack = new DefaultToolPack();
- usedToolPacks.add(defaultToolPack);
- usedToolPacks.add(new AnalysisToolPak());
- }
-
- /**
- * Checks if such function exists in any registered tool pack.
- * @param name Name of function.
- * @return true if some tool pack contains such function.
- */
- public boolean containsFunction(String name) {
- for (ToolPack pack : usedToolPacks) {
- if (pack.containsFunction(name)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Returns executor by specified name. Returns <code>null</code> if
- * function isn't contained by any registered tool pack.
- *
- * @param name
- * Name of function.
- * @return Function executor.
- */
- public FreeRefFunction findFunction(String name) {
- FreeRefFunction evaluatorForFunction;
- for (ToolPack pack : usedToolPacks) {
- evaluatorForFunction = pack.findFunction(name);
- if (evaluatorForFunction != null) {
- return evaluatorForFunction;
- }
- }
- return null;
- }
-
- /**
- * Registers new tool pack in handler.
- * @param pack Tool pack to add.
- */
- public void addToolPack(ToolPack pack) {
- usedToolPacks.add(pack);
- }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/udf/AggregatingUDFFinder.java b/src/java/org/apache/poi/hssf/record/formula/udf/AggregatingUDFFinder.java
new file mode 100755
index 0000000000..2dedf7b9d3
--- /dev/null
+++ b/src/java/org/apache/poi/hssf/record/formula/udf/AggregatingUDFFinder.java
@@ -0,0 +1,52 @@
+/* ====================================================================
+ 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.udf;
+
+import org.apache.poi.hssf.record.formula.functions.FreeRefFunction;
+
+/**
+ * Collects add-in libraries and VB macro functions together into one UDF finder
+ *
+ * @author PUdalau
+ */
+public final class AggregatingUDFFinder implements UDFFinder {
+
+ private final UDFFinder[] _usedToolPacks;
+
+ public AggregatingUDFFinder(UDFFinder ... usedToolPacks) {
+ _usedToolPacks = usedToolPacks.clone();
+ }
+
+ /**
+ * Returns executor by specified name. Returns <code>null</code> if
+ * function isn't contained by any registered tool pack.
+ *
+ * @param name Name of function.
+ * @return Function executor. <code>null</code> if not found
+ */
+ public FreeRefFunction findFunction(String name) {
+ FreeRefFunction evaluatorForFunction;
+ for (UDFFinder pack : _usedToolPacks) {
+ evaluatorForFunction = pack.findFunction(name);
+ if (evaluatorForFunction != null) {
+ return evaluatorForFunction;
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/java/org/apache/poi/hssf/record/formula/toolpack/DefaultToolPack.java b/src/java/org/apache/poi/hssf/record/formula/udf/DefaultUDFFinder.java
index 39d2c47ca9..f87027aeb7 100755
--- a/src/java/org/apache/poi/hssf/record/formula/toolpack/DefaultToolPack.java
+++ b/src/java/org/apache/poi/hssf/record/formula/udf/DefaultUDFFinder.java
@@ -15,7 +15,7 @@
limitations under the License.
==================================================================== */
-package org.apache.poi.hssf.record.formula.toolpack;
+package org.apache.poi.hssf.record.formula.udf;
import java.util.HashMap;
import java.util.Map;
@@ -23,29 +23,27 @@ import java.util.Map;
import org.apache.poi.hssf.record.formula.functions.FreeRefFunction;
/**
- * Default tool pack.
- * If you want to add some UDF, but you don't want to create new tool pack, use this.
- *
+ * Default UDF finder - for adding your own user defined functions.
+ *
* @author PUdalau
*/
-public class DefaultToolPack implements ToolPack {
- private Map<String, FreeRefFunction> functionsByName = new HashMap<String, FreeRefFunction>();
-
- public void addFunction(String name, FreeRefFunction evaluator) {
- if (evaluator != null){
- functionsByName.put(name, evaluator);
- }
- }
-
- public boolean containsFunction(String name) {
- return functionsByName.containsKey(name);
- }
-
- public FreeRefFunction findFunction(String name) {
- return functionsByName.get(name);
- }
-
- public void removeFunction(String name) {
- functionsByName.remove(name);
- }
+public final class DefaultUDFFinder implements UDFFinder {
+ private final Map<String, FreeRefFunction> _functionsByName;
+
+ public DefaultUDFFinder(String[] functionNames, FreeRefFunction[] functionImpls) {
+ int nFuncs = functionNames.length;
+ if (functionImpls.length != nFuncs) {
+ throw new IllegalArgumentException(
+ "Mismatch in number of function names and implementations");
+ }
+ HashMap<String, FreeRefFunction> m = new HashMap<String, FreeRefFunction>(nFuncs * 3 / 2);
+ for (int i = 0; i < functionImpls.length; i++) {
+ m.put(functionNames[i], functionImpls[i]);
+ }
+ _functionsByName = m;
+ }
+
+ public FreeRefFunction findFunction(String name) {
+ return _functionsByName.get(name);
+ }
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/toolpack/ToolPack.java b/src/java/org/apache/poi/hssf/record/formula/udf/UDFFinder.java
index d2e58da9e3..ba2882664f 100755
--- a/src/java/org/apache/poi/hssf/record/formula/toolpack/ToolPack.java
+++ b/src/java/org/apache/poi/hssf/record/formula/udf/UDFFinder.java
@@ -15,42 +15,24 @@
limitations under the License.
==================================================================== */
-package org.apache.poi.hssf.record.formula.toolpack;
+package org.apache.poi.hssf.record.formula.udf;
+import org.apache.poi.hssf.record.formula.atp.AnalysisToolPak;
import org.apache.poi.hssf.record.formula.functions.FreeRefFunction;
/**
- * Common interface for any new tool pack with executors for functions.
- *
+ * Common interface for "Add-in" libraries and user defined function libraries.
+ *
* @author PUdalau
*/
-public interface ToolPack {
+public interface UDFFinder {
+ public static final UDFFinder DEFAULT = new AggregatingUDFFinder(AnalysisToolPak.instance);
+
/**
- * Returns executor by specified name. Returns <code>null</code> if tool
- * pack doesn't contains such function.
- *
+ * Returns executor by specified name. Returns <code>null</code> if the function name is unknown.
+ *
* @param name Name of function.
* @return Function executor.
*/
FreeRefFunction findFunction(String name);
-
- /**
- * Add new function with executor.
- * @param name Name of function.
- * @param evaluator Function executor.
- */
- void addFunction(String name, FreeRefFunction evaluator);
-
- /**
- * Returns executor by specified name if it exists.
- * @param name Name of function.
- */
- void removeFunction(String name);
-
- /**
- * Checks if such function exists in tool pack.
- * @param name Name of function.
- * @return true if tool pack contains such function.
- */
- boolean containsFunction(String name);
}
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java b/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java
index b0f18bcda9..0184d1639b 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java
@@ -6,7 +6,7 @@
(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
+ 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,
@@ -24,146 +24,145 @@ import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate;
import org.apache.poi.hssf.record.formula.NamePtg;
import org.apache.poi.hssf.record.formula.NameXPtg;
import org.apache.poi.hssf.record.formula.Ptg;
-import org.apache.poi.hssf.record.formula.functions.FreeRefFunction;
-import org.apache.poi.ss.formula.*;
import org.apache.poi.ss.SpreadsheetVersion;
+import org.apache.poi.ss.formula.EvaluationCell;
+import org.apache.poi.ss.formula.EvaluationName;
+import org.apache.poi.ss.formula.EvaluationSheet;
+import org.apache.poi.ss.formula.EvaluationWorkbook;
+import org.apache.poi.ss.formula.FormulaParsingWorkbook;
+import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
+import org.apache.poi.ss.formula.FormulaType;
/**
* Internal POI use only
*
* @author Josh Micich
- *
- * Modified 09/07/09 by Petr Udalau - added methods for searching for UDFs of this Workbook.
*/
public final class HSSFEvaluationWorkbook implements FormulaRenderingWorkbook, EvaluationWorkbook, FormulaParsingWorkbook {
- private final HSSFWorkbook _uBook;
- private final Workbook _iBook;
-
- public static HSSFEvaluationWorkbook create(HSSFWorkbook book) {
- if (book == null) {
- return null;
- }
- return new HSSFEvaluationWorkbook(book);
- }
-
- private HSSFEvaluationWorkbook(HSSFWorkbook book) {
- _uBook = book;
- _iBook = book.getWorkbook();
- }
-
- public int getExternalSheetIndex(String sheetName) {
- int sheetIndex = _uBook.getSheetIndex(sheetName);
- return _iBook.checkExternSheet(sheetIndex);
- }
- public int getExternalSheetIndex(String workbookName, String sheetName) {
- return _iBook.getExternalSheetIndex(workbookName, sheetName);
- }
-
- public NameXPtg getNameXPtg(String name) {
- return _iBook.getNameXPtg(name);
- }
-
- /**
- * Lookup a named range by its name.
- *
- * @param name the name to search
- * @param sheetIndex the 0-based index of the sheet this formula belongs to.
- * The sheet index is required to resolve sheet-level names. <code>-1</code> means workbook-global names
- */
- public EvaluationName getName(String name, int sheetIndex) {
- for(int i=0; i < _iBook.getNumNames(); i++) {
- NameRecord nr = _iBook.getNameRecord(i);
- if (nr.getSheetNumber() == sheetIndex+1 && name.equalsIgnoreCase(nr.getNameText())) {
- return new Name(nr, i);
- }
- }
- return sheetIndex == -1 ? null : getName(name, -1);
- }
-
- public int getSheetIndex(EvaluationSheet evalSheet) {
- HSSFSheet sheet = ((HSSFEvaluationSheet)evalSheet).getHSSFSheet();
- return _uBook.getSheetIndex(sheet);
- }
- public int getSheetIndex(String sheetName) {
- return _uBook.getSheetIndex(sheetName);
- }
-
- public String getSheetName(int sheetIndex) {
- return _uBook.getSheetName(sheetIndex);
- }
-
- public EvaluationSheet getSheet(int sheetIndex) {
- return new HSSFEvaluationSheet(_uBook.getSheetAt(sheetIndex));
- }
- public int convertFromExternSheetIndex(int externSheetIndex) {
- return _iBook.getSheetIndexFromExternSheetIndex(externSheetIndex);
- }
-
- public ExternalSheet getExternalSheet(int externSheetIndex) {
- return _iBook.getExternalSheet(externSheetIndex);
- }
-
- public String resolveNameXText(NameXPtg n) {
- return _iBook.resolveNameXText(n.getSheetRefIndex(), n.getNameIndex());
- }
-
- public String getSheetNameByExternSheet(int externSheetIndex) {
- return _iBook.findSheetNameFromExternSheet(externSheetIndex);
- }
- public String getNameText(NamePtg namePtg) {
- return _iBook.getNameRecord(namePtg.getIndex()).getNameText();
- }
- public EvaluationName getName(NamePtg namePtg) {
- int ix = namePtg.getIndex();
- return new Name(_iBook.getNameRecord(ix), ix);
- }
- public Ptg[] getFormulaTokens(EvaluationCell evalCell) {
- HSSFCell cell = ((HSSFEvaluationCell)evalCell).getHSSFCell();
- if (false) {
- // re-parsing the formula text also works, but is a waste of time
- // It is useful from time to time to run all unit tests with this code
- // to make sure that all formulas POI can evaluate can also be parsed.
- return HSSFFormulaParser.parse(cell.getCellFormula(), _uBook, FormulaType.CELL, _uBook.getSheetIndex(cell.getSheet()));
- }
- FormulaRecordAggregate fra = (FormulaRecordAggregate) cell.getCellValueRecord();
- return fra.getFormulaTokens();
- }
-
- private static final class Name implements EvaluationName {
-
- private final NameRecord _nameRecord;
- private final int _index;
-
- public Name(NameRecord nameRecord, int index) {
- _nameRecord = nameRecord;
- _index = index;
- }
- public Ptg[] getNameDefinition() {
- return _nameRecord.getNameDefinition();
- }
- public String getNameText() {
- return _nameRecord.getNameText();
- }
- public boolean hasFormula() {
- return _nameRecord.hasFormula();
- }
- public boolean isFunctionName() {
- return _nameRecord.isFunctionName();
- }
- public boolean isRange() {
- return _nameRecord.hasFormula(); // TODO - is this right?
- }
- public NamePtg createPtg() {
- return new NamePtg(_index);
- }
- }
-
- public SpreadsheetVersion getSpreadsheetVersion(){
- return SpreadsheetVersion.EXCEL97;
- }
-
- public FreeRefFunction findUserDefinedFunction(String functionName) {
- return _uBook.getUserDefinedFunction(functionName);
- }
+ private final HSSFWorkbook _uBook;
+ private final Workbook _iBook;
+
+ public static HSSFEvaluationWorkbook create(HSSFWorkbook book) {
+ if (book == null) {
+ return null;
+ }
+ return new HSSFEvaluationWorkbook(book);
+ }
+
+ private HSSFEvaluationWorkbook(HSSFWorkbook book) {
+ _uBook = book;
+ _iBook = book.getWorkbook();
+ }
+
+ public int getExternalSheetIndex(String sheetName) {
+ int sheetIndex = _uBook.getSheetIndex(sheetName);
+ return _iBook.checkExternSheet(sheetIndex);
+ }
+ public int getExternalSheetIndex(String workbookName, String sheetName) {
+ return _iBook.getExternalSheetIndex(workbookName, sheetName);
+ }
+
+ public NameXPtg getNameXPtg(String name) {
+ return _iBook.getNameXPtg(name);
+ }
+
+ /**
+ * Lookup a named range by its name.
+ *
+ * @param name the name to search
+ * @param sheetIndex the 0-based index of the sheet this formula belongs to.
+ * The sheet index is required to resolve sheet-level names. <code>-1</code> means workbook-global names
+ */
+ public EvaluationName getName(String name, int sheetIndex) {
+ for(int i=0; i < _iBook.getNumNames(); i++) {
+ NameRecord nr = _iBook.getNameRecord(i);
+ if (nr.getSheetNumber() == sheetIndex+1 && name.equalsIgnoreCase(nr.getNameText())) {
+ return new Name(nr, i);
+ }
+ }
+ return sheetIndex == -1 ? null : getName(name, -1);
+ }
+
+ public int getSheetIndex(EvaluationSheet evalSheet) {
+ HSSFSheet sheet = ((HSSFEvaluationSheet)evalSheet).getHSSFSheet();
+ return _uBook.getSheetIndex(sheet);
+ }
+ public int getSheetIndex(String sheetName) {
+ return _uBook.getSheetIndex(sheetName);
+ }
+
+ public String getSheetName(int sheetIndex) {
+ return _uBook.getSheetName(sheetIndex);
+ }
+
+ public EvaluationSheet getSheet(int sheetIndex) {
+ return new HSSFEvaluationSheet(_uBook.getSheetAt(sheetIndex));
+ }
+ public int convertFromExternSheetIndex(int externSheetIndex) {
+ return _iBook.getSheetIndexFromExternSheetIndex(externSheetIndex);
+ }
+
+ public ExternalSheet getExternalSheet(int externSheetIndex) {
+ return _iBook.getExternalSheet(externSheetIndex);
+ }
+
+ public String resolveNameXText(NameXPtg n) {
+ return _iBook.resolveNameXText(n.getSheetRefIndex(), n.getNameIndex());
+ }
+
+ public String getSheetNameByExternSheet(int externSheetIndex) {
+ return _iBook.findSheetNameFromExternSheet(externSheetIndex);
+ }
+ public String getNameText(NamePtg namePtg) {
+ return _iBook.getNameRecord(namePtg.getIndex()).getNameText();
+ }
+ public EvaluationName getName(NamePtg namePtg) {
+ int ix = namePtg.getIndex();
+ return new Name(_iBook.getNameRecord(ix), ix);
+ }
+ public Ptg[] getFormulaTokens(EvaluationCell evalCell) {
+ HSSFCell cell = ((HSSFEvaluationCell)evalCell).getHSSFCell();
+ if (false) {
+ // re-parsing the formula text also works, but is a waste of time
+ // It is useful from time to time to run all unit tests with this code
+ // to make sure that all formulas POI can evaluate can also be parsed.
+ return HSSFFormulaParser.parse(cell.getCellFormula(), _uBook, FormulaType.CELL, _uBook.getSheetIndex(cell.getSheet()));
+ }
+ FormulaRecordAggregate fra = (FormulaRecordAggregate) cell.getCellValueRecord();
+ return fra.getFormulaTokens();
+ }
+
+ private static final class Name implements EvaluationName {
+
+ private final NameRecord _nameRecord;
+ private final int _index;
+
+ public Name(NameRecord nameRecord, int index) {
+ _nameRecord = nameRecord;
+ _index = index;
+ }
+ public Ptg[] getNameDefinition() {
+ return _nameRecord.getNameDefinition();
+ }
+ public String getNameText() {
+ return _nameRecord.getNameText();
+ }
+ public boolean hasFormula() {
+ return _nameRecord.hasFormula();
+ }
+ public boolean isFunctionName() {
+ return _nameRecord.isFunctionName();
+ }
+ public boolean isRange() {
+ return _nameRecord.hasFormula(); // TODO - is this right?
+ }
+ public NamePtg createPtg() {
+ return new NamePtg(_index);
+ }
+ }
+
+ public SpreadsheetVersion getSpreadsheetVersion(){
+ return SpreadsheetVersion.EXCEL97;
+ }
}
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java b/src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java
index a49fb9c684..16b5a5a0dc 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java
@@ -24,6 +24,7 @@ import org.apache.poi.hssf.record.formula.eval.ErrorEval;
import org.apache.poi.hssf.record.formula.eval.NumberEval;
import org.apache.poi.hssf.record.formula.eval.StringEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
+import org.apache.poi.hssf.record.formula.udf.UDFFinder;
import org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment;
import org.apache.poi.ss.formula.IStabilityClassifier;
import org.apache.poi.ss.formula.WorkbookEvaluator;
@@ -64,10 +65,28 @@ public class HSSFFormulaEvaluator implements FormulaEvaluator {
* evaluation begins.
*/
public HSSFFormulaEvaluator(HSSFWorkbook workbook, IStabilityClassifier stabilityClassifier) {
- _bookEvaluator = new WorkbookEvaluator(HSSFEvaluationWorkbook.create(workbook), stabilityClassifier);
+ this(workbook, stabilityClassifier, null);
}
/**
+ * @param udfFinder pass <code>null</code> for default (AnalysisToolPak only)
+ */
+ private HSSFFormulaEvaluator(HSSFWorkbook workbook, IStabilityClassifier stabilityClassifier, UDFFinder udfFinder) {
+ _bookEvaluator = new WorkbookEvaluator(HSSFEvaluationWorkbook.create(workbook), stabilityClassifier, udfFinder);
+ }
+
+ /**
+ * @param stabilityClassifier used to optimise caching performance. Pass <code>null</code>
+ * for the (conservative) assumption that any cell may have its definition changed after
+ * evaluation begins.
+ * @param udfFinder pass <code>null</code> for default (AnalysisToolPak only)
+ */
+ public static HSSFFormulaEvaluator create(HSSFWorkbook workbook, IStabilityClassifier stabilityClassifier, UDFFinder udfFinder) {
+ return new HSSFFormulaEvaluator(workbook, stabilityClassifier, udfFinder);
+ }
+
+
+ /**
* Coordinates several formula evaluators together so that formulas that involve external
* references can be evaluated.
* @param workbookNames the simple file names used to identify the workbooks in formulas
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
index b9a732bc32..cb772c9b84 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
@@ -24,11 +24,9 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
-import java.util.Map;
import java.util.regex.Pattern;
import org.apache.poi.POIDocument;
@@ -64,12 +62,10 @@ import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.hssf.record.formula.Ref3DPtg;
import org.apache.poi.hssf.record.formula.SheetNameFormatter;
import org.apache.poi.hssf.record.formula.UnionPtg;
-import org.apache.poi.hssf.record.formula.functions.FreeRefFunction;
import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.CreationHelper;
-import org.apache.poi.ss.usermodel.Name;
import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
import org.apache.poi.ss.formula.FormulaType;
import org.apache.poi.util.POILogFactory;
@@ -86,9 +82,6 @@ import org.apache.poi.util.POILogger;
* @author Andrew C. Oliver (acoliver at apache dot org)
* @author Glen Stampoultzis (glens at apache.org)
* @author Shawn Laubach (slaubach at apache dot org)
- *
- *
- * Modified 09/07/09 by Petr Udalau - added methods for work with UDFs of this Workbook.
*/
public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.usermodel.Workbook {
private static final Pattern COMMA_PATTERN = Pattern.compile(",");
@@ -167,9 +160,6 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
private static POILogger log = POILogFactory.getLogger(HSSFWorkbook.class);
-
- /** Map of user defined functions, key - function name, value - instance of FreeRefFunctions */
- private Map<String, FreeRefFunction> udfFunctions;
/**
* Creates new HSSFWorkbook from scratch (start here!)
@@ -186,7 +176,6 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
workbook = book;
_sheets = new ArrayList( INITIAL_CAPACITY );
names = new ArrayList( INITIAL_CAPACITY );
- udfFunctions = new HashMap<String, FreeRefFunction>();
}
public HSSFWorkbook(POIFSFileSystem fs) throws IOException {
@@ -278,7 +267,6 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
_sheets = new ArrayList(INITIAL_CAPACITY);
names = new ArrayList(INITIAL_CAPACITY);
- udfFunctions = new HashMap<String, FreeRefFunction>();
// Grab the data from the workbook stream, however
// it happens to be spelled.
@@ -1627,25 +1615,6 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
}
}
}
-
- public FreeRefFunction getUserDefinedFunction(String functionName) {
- return udfFunctions.get(functionName);
- }
-
- public void registerUserDefinedFunction(String functionName, FreeRefFunction freeRefFunction) {
- Name udfDeclaration = getName(functionName);
- if (udfDeclaration == null) {
- udfDeclaration = createName();
- }
- udfDeclaration.setNameName(functionName);
- udfDeclaration.setFunction(true);
- udfFunctions.put(functionName, freeRefFunction);
-
- }
-
- public List<String> getUserDefinedFunctionNames() {
- return new ArrayList<String>(udfFunctions.keySet());
- }
/**
* Is the workbook protected with a password (not encrypted)?
@@ -1729,5 +1698,4 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
public NameXPtg getNameXPtg(String name) {
return workbook.getNameXPtg(name);
}
-
}
diff --git a/src/java/org/apache/poi/ss/formula/EvaluationWorkbook.java b/src/java/org/apache/poi/ss/formula/EvaluationWorkbook.java
index 0d65af92df..a3b2325719 100644
--- a/src/java/org/apache/poi/ss/formula/EvaluationWorkbook.java
+++ b/src/java/org/apache/poi/ss/formula/EvaluationWorkbook.java
@@ -20,7 +20,6 @@ package org.apache.poi.ss.formula;
import org.apache.poi.hssf.record.formula.NamePtg;
import org.apache.poi.hssf.record.formula.NameXPtg;
import org.apache.poi.hssf.record.formula.Ptg;
-import org.apache.poi.hssf.record.formula.functions.FreeRefFunction;
/**
* Abstracts a workbook for the purpose of formula evaluation.<br/>
@@ -28,8 +27,6 @@ import org.apache.poi.hssf.record.formula.functions.FreeRefFunction;
* For POI internal use only
*
* @author Josh Micich
- *
- * Modified 09/07/09 by Petr Udalau - added methods for searching for UDFs of this Workbook.
*/
public interface EvaluationWorkbook {
String getSheetName(int sheetIndex);
@@ -54,17 +51,6 @@ public interface EvaluationWorkbook {
String resolveNameXText(NameXPtg ptg);
Ptg[] getFormulaTokens(EvaluationCell cell);
- /**
- * Find and return user defined function (UDF) contained by workbook with
- * specified name.
- *
- * @param functionName UDF name
- * @return instance of FreeRefFunction or null if no UDF with the specified
- * name exists.
- */
- FreeRefFunction findUserDefinedFunction(String functionName);
-
-
class ExternalSheet {
private final String _workbookName;
private final String _sheetName;
diff --git a/src/java/org/apache/poi/ss/formula/OperationEvaluationContext.java b/src/java/org/apache/poi/ss/formula/OperationEvaluationContext.java
index 2ec5f5791c..e1a28a6fee 100644
--- a/src/java/org/apache/poi/ss/formula/OperationEvaluationContext.java
+++ b/src/java/org/apache/poi/ss/formula/OperationEvaluationContext.java
@@ -22,6 +22,7 @@ import org.apache.poi.hssf.record.formula.eval.AreaEval;
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
import org.apache.poi.hssf.record.formula.eval.RefEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
+import org.apache.poi.hssf.record.formula.functions.FreeRefFunction;
import org.apache.poi.ss.SpreadsheetVersion;
import org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment.WorkbookNotFoundException;
import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalSheet;
@@ -256,4 +257,8 @@ public final class OperationEvaluationContext {
}
return CellReference.classifyCellReference(str, ssVersion);
}
+
+ public FreeRefFunction findUserDefinedFunction(String functionName) {
+ return _bookEvaluator.findUserDefinedFunction(functionName);
+ }
}
diff --git a/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java b/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java
index 806c002bb1..ed8abb7dfa 100644
--- a/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java
+++ b/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java
@@ -59,6 +59,8 @@ import org.apache.poi.hssf.record.formula.eval.OperationEval;
import org.apache.poi.hssf.record.formula.eval.RefEval;
import org.apache.poi.hssf.record.formula.eval.StringEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
+import org.apache.poi.hssf.record.formula.functions.FreeRefFunction;
+import org.apache.poi.hssf.record.formula.udf.UDFFinder;
import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment.WorkbookNotFoundException;
import org.apache.poi.ss.formula.eval.NotImplementedException;
@@ -87,12 +89,16 @@ public final class WorkbookEvaluator {
private final Map<String, Integer> _sheetIndexesByName;
private CollaboratingWorkbooksEnvironment _collaboratingWorkbookEnvironment;
private final IStabilityClassifier _stabilityClassifier;
+ private final UDFFinder _udfFinder;
- public WorkbookEvaluator(EvaluationWorkbook workbook, IStabilityClassifier stabilityClassifier) {
- this (workbook, null, stabilityClassifier);
+ /**
+ * @param udfFinder pass <code>null</code> for default (AnalysisToolPak only)
+ */
+ public WorkbookEvaluator(EvaluationWorkbook workbook, IStabilityClassifier stabilityClassifier, UDFFinder udfFinder) {
+ this (workbook, null, stabilityClassifier, udfFinder);
}
/* package */ WorkbookEvaluator(EvaluationWorkbook workbook, IEvaluationListener evaluationListener,
- IStabilityClassifier stabilityClassifier) {
+ IStabilityClassifier stabilityClassifier, UDFFinder udfFinder) {
_workbook = workbook;
_evaluationListener = evaluationListener;
_cache = new EvaluationCache(evaluationListener);
@@ -101,6 +107,7 @@ public final class WorkbookEvaluator {
_collaboratingWorkbookEnvironment = CollaboratingWorkbooksEnvironment.EMPTY;
_workbookIx = 0;
_stabilityClassifier = stabilityClassifier;
+ _udfFinder = udfFinder == null ? UDFFinder.DEFAULT : udfFinder;
}
/**
@@ -516,4 +523,7 @@ public final class WorkbookEvaluator {
EvaluationCell cell = sheet.getCell(rowIndex, columnIndex);
return evaluateAny(cell, sheetIndex, rowIndex, columnIndex, tracker);
}
+ public FreeRefFunction findUserDefinedFunction(String functionName) {
+ return _udfFinder.findFunction(functionName);
+ }
}
diff --git a/src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationWorkbook.java b/src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationWorkbook.java
index 1525708f31..08ed7f5346 100644
--- a/src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationWorkbook.java
+++ b/src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationWorkbook.java
@@ -36,8 +36,6 @@ import org.apache.poi.ss.usermodel.Workbook;
* updated after a call to {@link #getOrCreateUpdatableCell(String, int, int)}.
*
* @author Josh Micich
- *
- * Modified 09/07/09 by Petr Udalau - added methods for searching for UDFs of this Workbook.
*/
final class ForkedEvaluationWorkbook implements EvaluationWorkbook {
@@ -144,8 +142,4 @@ final class ForkedEvaluationWorkbook implements EvaluationWorkbook {
return _index - o._index;
}
}
-
- public FreeRefFunction findUserDefinedFunction(String functionName) {
- return _masterBook.findUserDefinedFunction(functionName);
- }
}
diff --git a/src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluator.java b/src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluator.java
index e89d2a6104..7985603748 100644
--- a/src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluator.java
+++ b/src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluator.java
@@ -22,6 +22,7 @@ import org.apache.poi.hssf.record.formula.eval.ErrorEval;
import org.apache.poi.hssf.record.formula.eval.NumberEval;
import org.apache.poi.hssf.record.formula.eval.StringEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
+import org.apache.poi.hssf.record.formula.udf.UDFFinder;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFEvaluationWorkbook;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
@@ -47,9 +48,9 @@ public final class ForkedEvaluator {
private WorkbookEvaluator _evaluator;
private ForkedEvaluationWorkbook _sewb;
- private ForkedEvaluator(EvaluationWorkbook masterWorkbook, IStabilityClassifier stabilityClassifier) {
+ private ForkedEvaluator(EvaluationWorkbook masterWorkbook, IStabilityClassifier stabilityClassifier, UDFFinder udfFinder) {
_sewb = new ForkedEvaluationWorkbook(masterWorkbook);
- _evaluator = new WorkbookEvaluator(_sewb, stabilityClassifier);
+ _evaluator = new WorkbookEvaluator(_sewb, stabilityClassifier, udfFinder);
}
private static EvaluationWorkbook createEvaluationWorkbook(Workbook wb) {
if (wb instanceof HSSFWorkbook) {
@@ -61,8 +62,17 @@ public final class ForkedEvaluator {
// }
throw new IllegalArgumentException("Unexpected workbook type (" + wb.getClass().getName() + ")");
}
+ /**
+ * @deprecated (Sep 2009) (reduce overloading) use {@link #create(Workbook, IStabilityClassifier, UDFFinder)}
+ */
public static ForkedEvaluator create(Workbook wb, IStabilityClassifier stabilityClassifier) {
- return new ForkedEvaluator(createEvaluationWorkbook(wb), stabilityClassifier);
+ return create(wb, stabilityClassifier, null);
+ }
+ /**
+ * @param udfFinder pass <code>null</code> for default (AnalysisToolPak only)
+ */
+ public static ForkedEvaluator create(Workbook wb, IStabilityClassifier stabilityClassifier, UDFFinder udfFinder) {
+ return new ForkedEvaluator(createEvaluationWorkbook(wb), stabilityClassifier, udfFinder);
}
/**
diff --git a/src/java/org/apache/poi/ss/usermodel/Name.java b/src/java/org/apache/poi/ss/usermodel/Name.java
index 0cc9d98e9e..a07154e5fe 100644
--- a/src/java/org/apache/poi/ss/usermodel/Name.java
+++ b/src/java/org/apache/poi/ss/usermodel/Name.java
@@ -49,8 +49,6 @@ package org.apache.poi.ss.usermodel;
* name.setRefersToFormula("IF(Loan_Amount*Interest_Rate>0,1,0)");
*
* </blockquote></pre>
- *
- * Modified 8/31/09 by Petr Udalau - added method setFunction(boolean)
*/
public interface Name {
@@ -61,14 +59,14 @@ public interface Name {
*/
String getSheetName();
- /**
+ /**
* Gets the name of the named range
*
* @return named range name
*/
String getNameName();
- /**
+ /**
* Sets the name of the named range
*
* <p>The following is a list of syntax rules that you need to be aware of when you create and edit names.</p>
@@ -118,7 +116,7 @@ public interface Name {
void setNameName(String name);
/**
- * Returns the formula that the name is defined to refer to.
+ * Returns the formula that the name is defined to refer to.
*
* @return the reference for this name, <code>null</code> if it has not been set yet. Never empty string
* @see #setRefersToFormula(String)
diff --git a/src/java/org/apache/poi/ss/usermodel/Workbook.java b/src/java/org/apache/poi/ss/usermodel/Workbook.java
index cbbc2a4268..99f4ddba89 100644
--- a/src/java/org/apache/poi/ss/usermodel/Workbook.java
+++ b/src/java/org/apache/poi/ss/usermodel/Workbook.java
@@ -21,15 +21,12 @@ import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
-import org.apache.poi.hssf.record.formula.functions.FreeRefFunction;
import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
/**
* High level representation of a Excel workbook. This is the first object most users
* will construct whether they are reading or writing a workbook. It is also the
* top level object for creating new sheets/etc.
- *
- * Modified 09/07/09 by Petr Udalau - added methods for work with UDFs of this Workbook.
*/
public interface Workbook {
@@ -189,7 +186,7 @@ public interface Workbook {
* @param index of the sheet to remove (0-based)
*/
void removeSheetAt(int index);
-
+
/**
* Sets the repeating rows and columns for a sheet (as found in
* File->PageSetup->Sheet). This is function is included in the workbook
@@ -374,7 +371,7 @@ public interface Workbook {
* Sets the policy on what to do when
* getting missing or blank cells from a row.
*
- * This will then apply to all calls to
+ * This will then apply to all calls to
* {@link Row#getCell(int)} }. See
* {@link MissingCellPolicy}
*/
@@ -467,29 +464,4 @@ public interface Workbook {
* @param hidden 0 for not hidden, 1 for hidden, 2 for very hidden
*/
void setSheetHidden(int sheetIx, int hidden);
-
- /**
- * Find and return user defined function (UDF) with specified name.
- *
- * @param functionName
- * UDF name
- * @return instance of FreeRefFunction or null if no UDF with the specified
- * name exists.
- */
- FreeRefFunction getUserDefinedFunction(String functionName);
-
- /**
- * Add user defined function (UDF) to workbook
- *
- * @param name
- * @param function
- */
- void registerUserDefinedFunction(String name, FreeRefFunction function);
-
- /**
- * Returns user defined functions (UDF) names
- *
- * @return list of UDF names
- */
- List<String> getUserDefinedFunctionNames();
}
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationWorkbook.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationWorkbook.java
index 5e6fd93904..5264281f00 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationWorkbook.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationWorkbook.java
@@ -20,7 +20,6 @@ package org.apache.poi.xssf.usermodel;
import org.apache.poi.hssf.record.formula.NamePtg;
import org.apache.poi.hssf.record.formula.NameXPtg;
import org.apache.poi.hssf.record.formula.Ptg;
-import org.apache.poi.hssf.record.formula.functions.FreeRefFunction;
import org.apache.poi.ss.formula.*;
import org.apache.poi.ss.SpreadsheetVersion;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDefinedName;
@@ -29,8 +28,6 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDefinedName;
* Internal POI use only
*
* @author Josh Micich
- *
- * Modified 09/07/09 by Petr Udalau - added methods for searching for UDFs of this Workbook.
*/
public final class XSSFEvaluationWorkbook implements FormulaRenderingWorkbook, EvaluationWorkbook, FormulaParsingWorkbook {
@@ -180,8 +177,4 @@ public final class XSSFEvaluationWorkbook implements FormulaRenderingWorkbook, E
public SpreadsheetVersion getSpreadsheetVersion(){
return SpreadsheetVersion.EXCEL2007;
}
-
- public FreeRefFunction findUserDefinedFunction(String functionName) {
- return _uBook.getUserDefinedFunction(functionName);
- }
}
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFFormulaEvaluator.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFFormulaEvaluator.java
index 8780ae23f3..0130eca232 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFFormulaEvaluator.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFFormulaEvaluator.java
@@ -24,6 +24,8 @@ import org.apache.poi.hssf.record.formula.eval.ErrorEval;
import org.apache.poi.hssf.record.formula.eval.NumberEval;
import org.apache.poi.hssf.record.formula.eval.StringEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
+import org.apache.poi.hssf.record.formula.udf.UDFFinder;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.formula.IStabilityClassifier;
import org.apache.poi.ss.formula.WorkbookEvaluator;
import org.apache.poi.ss.usermodel.Cell;
@@ -47,16 +49,31 @@ public class XSSFFormulaEvaluator implements FormulaEvaluator {
private WorkbookEvaluator _bookEvaluator;
public XSSFFormulaEvaluator(XSSFWorkbook workbook) {
- this(workbook, null);
+ this(workbook, null, null);
}
/**
* @param stabilityClassifier used to optimise caching performance. Pass <code>null</code>
- * for the (conservative) assumption that any cell may have its definition changed after
+ * for the (conservative) assumption that any cell may have its definition changed after
* evaluation begins.
+ * @deprecated (Sep 2009) (reduce overloading) use {@link #create(HSSFWorkbook, IStabilityClassifier, UDFFinder)}
*/
public XSSFFormulaEvaluator(XSSFWorkbook workbook, IStabilityClassifier stabilityClassifier) {
- _bookEvaluator = new WorkbookEvaluator(XSSFEvaluationWorkbook.create(workbook), stabilityClassifier);
+ _bookEvaluator = new WorkbookEvaluator(XSSFEvaluationWorkbook.create(workbook), stabilityClassifier, null);
}
+ private XSSFFormulaEvaluator(XSSFWorkbook workbook, IStabilityClassifier stabilityClassifier, UDFFinder udfFinder) {
+ _bookEvaluator = new WorkbookEvaluator(XSSFEvaluationWorkbook.create(workbook), stabilityClassifier, udfFinder);
+ }
+
+ /**
+ * @param stabilityClassifier used to optimise caching performance. Pass <code>null</code>
+ * for the (conservative) assumption that any cell may have its definition changed after
+ * evaluation begins.
+ * @param udfFinder pass <code>null</code> for default (AnalysisToolPak only)
+ */
+ public static XSSFFormulaEvaluator create(XSSFWorkbook workbook, IStabilityClassifier stabilityClassifier, UDFFinder udfFinder) {
+ return new XSSFFormulaEvaluator(workbook, stabilityClassifier, udfFinder);
+ }
+
/**
* Should be called whenever there are major changes (e.g. moving sheets) to input cells
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
index ffd1736119..67d4f69bf0 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
@@ -32,7 +32,6 @@ import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.POIXMLException;
import org.apache.poi.POIXMLProperties;
import org.apache.poi.hssf.record.formula.SheetNameFormatter;
-import org.apache.poi.hssf.record.formula.functions.FreeRefFunction;
import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackagePart;
@@ -41,7 +40,6 @@ import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
import org.apache.poi.openxml4j.opc.PackagingURIHelper;
import org.apache.poi.openxml4j.opc.TargetMode;
-import org.apache.poi.ss.usermodel.Name;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
@@ -65,8 +63,6 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.*;
* High level representation of a SpreadsheetML workbook. This is the first object most users
* will construct whether they are reading or writing a workbook. It is also the
* top level object for creating new sheets/etc.
- *
- * Modified 09/07/09 by Petr Udalau - added methods for work with UDFs of this Workbook.
*/
public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<XSSFSheet> {
private static final Pattern COMMA_PATTERN = Pattern.compile(",");
@@ -133,9 +129,6 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X
private List<XSSFPictureData> pictures;
private static POILogger logger = POILogFactory.getLogger(XSSFWorkbook.class);
-
- /** Map of user defined functions, key - function name, value - instance of FreeRefFunctions */
- private Map<String, FreeRefFunction> udfFunctions = new HashMap<String, FreeRefFunction>();
/**
* Create a new SpreadsheetML workbook.
@@ -1352,23 +1345,4 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X
public MapInfo getMapInfo(){
return mapInfo;
}
-
- public FreeRefFunction getUserDefinedFunction(String functionName) {
- return udfFunctions.get(functionName);
- }
-
- public void registerUserDefinedFunction(String functionName, FreeRefFunction freeRefFunction) {
- Name udfDeclaration = getName(functionName);
- if (udfDeclaration == null) {
- udfDeclaration = createName();
- }
- udfDeclaration.setNameName(functionName);
- udfDeclaration.setFunction(true);
- udfFunctions.put(functionName, freeRefFunction);
- }
-
- public List<String> getUserDefinedFunctionNames() {
- return new ArrayList<String>(udfFunctions.keySet());
- }
-
}
diff --git a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestExternalFunction.java b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestExternalFunction.java
index b2937b0fcb..2cfbbfec41 100644
--- a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestExternalFunction.java
+++ b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestExternalFunction.java
@@ -17,97 +17,79 @@
package org.apache.poi.hssf.record.formula.eval;
-import java.io.IOException;
-
import junit.framework.TestCase;
import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.hssf.record.formula.functions.FreeRefFunction;
-import org.apache.poi.hssf.record.formula.toolpack.DefaultToolPack;
-import org.apache.poi.hssf.record.formula.toolpack.MainToolPacksHandler;
-import org.apache.poi.hssf.record.formula.toolpack.ToolPack;
+import org.apache.poi.hssf.record.formula.udf.DefaultUDFFinder;
+import org.apache.poi.hssf.record.formula.udf.AggregatingUDFFinder;
+import org.apache.poi.hssf.record.formula.udf.UDFFinder;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.formula.OperationEvaluationContext;
-import org.apache.poi.ss.usermodel.Workbook;
/**
- *
* @author Josh Micich
- *
- * Modified 09/14/09 by Petr Udalau - Test of registering UDFs in workbook and
- * using ToolPacks.
+ * @author Petr Udalau - registering UDFs in workbook and using ToolPacks.
*/
public final class TestExternalFunction extends TestCase {
- private static class MyFunc implements FreeRefFunction {
- public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) {
- if (args.length != 1 || !(args[0] instanceof StringEval)) {
- return ErrorEval.VALUE_INVALID;
- } else {
- StringEval input = (StringEval) args[0];
- return new StringEval(input.getStringValue() + "abc");
- }
- }
- }
-
- private static class MyFunc2 implements FreeRefFunction {
- public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) {
- if (args.length != 1 || !(args[0] instanceof StringEval)) {
- return ErrorEval.VALUE_INVALID;
- } else {
- StringEval input = (StringEval) args[0];
- return new StringEval(input.getStringValue() + "abc2");
- }
- }
- }
-
- /**
- * Creates and registers user-defined function "MyFunc()" directly with POI.
- * This is VB function defined in "testNames.xls". In future there must be
- * some parser of VBA scripts which will register UDFs.
- */
- private void registerMyFunc(Workbook workbook) {
- workbook.registerUserDefinedFunction("myFunc", new MyFunc());
- }
-
- /**
- * Creates example ToolPack which contains function "MyFunc2()".
- */
- private void createExampleToolPack() {
- ToolPack exampleToolPack = new DefaultToolPack();
- exampleToolPack.addFunction("myFunc2", new MyFunc2());
- MainToolPacksHandler.instance().addToolPack(exampleToolPack);
- }
-
- /**
- * Checks that an external function can get invoked from the formula
- * evaluator.
- *
- * @throws IOException
- *
- */
- public void testInvoke() {
- HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("testNames.xls");
- HSSFSheet sheet = wb.getSheetAt(0);
-
- registerMyFunc(wb);
- createExampleToolPack();
-
- HSSFRow row = sheet.getRow(0);
- HSSFCell myFuncCell = row.getCell(1); //=myFunc("_")
-
- HSSFCell myFunc2Cell = row.getCell(2); //=myFunc2("_")
-
- HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
- try {
- assertEquals("_abc", fe.evaluate(myFuncCell).getStringValue());
- assertEquals("_abc2", fe.evaluate(myFunc2Cell).getStringValue());
- } catch (Exception e) {
- assertFalse(true);
- }
- }
+ private static class MyFunc implements FreeRefFunction {
+ public MyFunc() {
+ //
+ }
+
+ public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) {
+ if (args.length != 1 || !(args[0] instanceof StringEval)) {
+ return ErrorEval.VALUE_INVALID;
+ }
+ StringEval input = (StringEval) args[0];
+ return new StringEval(input.getStringValue() + "abc");
+ }
+ }
+
+ private static class MyFunc2 implements FreeRefFunction {
+ public MyFunc2() {
+ //
+ }
+
+ public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) {
+ if (args.length != 1 || !(args[0] instanceof StringEval)) {
+ return ErrorEval.VALUE_INVALID;
+ }
+ StringEval input = (StringEval) args[0];
+ return new StringEval(input.getStringValue() + "abc2");
+ }
+ }
+
+ /**
+ * Checks that an external function can get invoked from the formula
+ * evaluator.
+ */
+ public void testInvoke() {
+ HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("testNames.xls");
+ HSSFSheet sheet = wb.getSheetAt(0);
+
+ /**
+ * register the two test UDFs in a UDF finder, to be passed to the evaluator
+ */
+ UDFFinder udff1 = new DefaultUDFFinder(new String[] { "myFunc", },
+ new FreeRefFunction[] { new MyFunc(), });
+ UDFFinder udff2 = new DefaultUDFFinder(new String[] { "myFunc2", },
+ new FreeRefFunction[] { new MyFunc2(), });
+ UDFFinder udff = new AggregatingUDFFinder(udff1, udff2);
+
+
+ HSSFRow row = sheet.getRow(0);
+ HSSFCell myFuncCell = row.getCell(1); // =myFunc("_")
+
+ HSSFCell myFunc2Cell = row.getCell(2); // =myFunc2("_")
+
+ HSSFFormulaEvaluator fe = HSSFFormulaEvaluator.create(wb, null, udff);
+ assertEquals("_abc", fe.evaluate(myFuncCell).getStringValue());
+ assertEquals("_abc2", fe.evaluate(myFunc2Cell).getStringValue());
+ }
}
diff --git a/src/testcases/org/apache/poi/ss/formula/TestWorkbookEvaluator.java b/src/testcases/org/apache/poi/ss/formula/TestWorkbookEvaluator.java
index 9035ecbedb..41aa0ab57b 100644
--- a/src/testcases/org/apache/poi/ss/formula/TestWorkbookEvaluator.java
+++ b/src/testcases/org/apache/poi/ss/formula/TestWorkbookEvaluator.java
@@ -44,7 +44,7 @@ public class TestWorkbookEvaluator extends TestCase {
private static ValueEval evaluateFormula(Ptg[] ptgs) {
OperationEvaluationContext ec = new OperationEvaluationContext(null, null, 0, 0, 0, null);
- return new WorkbookEvaluator(null, null).evaluateFormula(ec, ptgs);
+ return new WorkbookEvaluator(null, null, null).evaluateFormula(ec, ptgs);
}
/**
diff --git a/src/testcases/org/apache/poi/ss/formula/WorkbookEvaluatorTestHelper.java b/src/testcases/org/apache/poi/ss/formula/WorkbookEvaluatorTestHelper.java
index b8b5de991e..673cb9500c 100644
--- a/src/testcases/org/apache/poi/ss/formula/WorkbookEvaluatorTestHelper.java
+++ b/src/testcases/org/apache/poi/ss/formula/WorkbookEvaluatorTestHelper.java
@@ -22,7 +22,7 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook;
/**
* Allows tests to execute {@link WorkbookEvaluator}s and track the internal workings.
- *
+ *
* @author Josh Micich
*/
public final class WorkbookEvaluatorTestHelper {
@@ -30,8 +30,8 @@ public final class WorkbookEvaluatorTestHelper {
private WorkbookEvaluatorTestHelper() {
// no instances of this class
}
-
+
public static WorkbookEvaluator createEvaluator(HSSFWorkbook wb, EvaluationListener listener) {
- return new WorkbookEvaluator(HSSFEvaluationWorkbook.create(wb), listener, null);
+ return new WorkbookEvaluator(HSSFEvaluationWorkbook.create(wb), listener, null, null);
}
}