You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by ye...@apache.org on 2012/02/21 10:43:02 UTC

svn commit: r1291677 - in /poi/trunk/src: documentation/content/xdocs/status.xml java/org/apache/poi/ss/formula/atp/AnalysisToolPak.java java/org/apache/poi/ss/formula/eval/FunctionEval.java testcases/org/apache/poi/ss/formula/TestFunctionRegistry.java

Author: yegor
Date: Tue Feb 21 09:43:01 2012
New Revision: 1291677

URL: http://svn.apache.org/viewvc?rev=1291677&view=rev
Log:
allow runtime registration of functions in FormulaEvaluator

Added:
    poi/trunk/src/testcases/org/apache/poi/ss/formula/TestFunctionRegistry.java
Modified:
    poi/trunk/src/documentation/content/xdocs/status.xml
    poi/trunk/src/java/org/apache/poi/ss/formula/atp/AnalysisToolPak.java
    poi/trunk/src/java/org/apache/poi/ss/formula/eval/FunctionEval.java

Modified: poi/trunk/src/documentation/content/xdocs/status.xml
URL: http://svn.apache.org/viewvc/poi/trunk/src/documentation/content/xdocs/status.xml?rev=1291677&r1=1291676&r2=1291677&view=diff
==============================================================================
--- poi/trunk/src/documentation/content/xdocs/status.xml (original)
+++ poi/trunk/src/documentation/content/xdocs/status.xml Tue Feb 21 09:43:01 2012
@@ -34,6 +34,7 @@
 
     <changes>
         <release version="3.8-beta6" date="2012-??-??">
+           <action dev="poi-developers" type="add"> allow runtime registration of functions in FormulaEvaluator</action>
            <action dev="poi-developers" type="fix">52665 - When reading from a ZipFileZipEntrySource that has already been closed, give IllegalArgumentException rather than NPE</action>
            <action dev="poi-developers" type="fix">52664 - MAPIMessage may not always have name chunks when checking for 7 bit encodings</action>
            <action dev="poi-developers" type="fix">52649 - fixed namespace issue in WordToFoConverter</action>

Modified: poi/trunk/src/java/org/apache/poi/ss/formula/atp/AnalysisToolPak.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/ss/formula/atp/AnalysisToolPak.java?rev=1291677&r1=1291676&r2=1291677&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/ss/formula/atp/AnalysisToolPak.java (original)
+++ poi/trunk/src/java/org/apache/poi/ss/formula/atp/AnalysisToolPak.java Tue Feb 21 09:43:01 2012
@@ -10,11 +10,16 @@
 
 package org.apache.poi.ss.formula.atp;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Map;
 
 import org.apache.poi.ss.formula.eval.ValueEval;
+import org.apache.poi.ss.formula.function.FunctionMetadata;
+import org.apache.poi.ss.formula.function.FunctionMetadataRegistry;
 import org.apache.poi.ss.formula.functions.FreeRefFunction;
+import org.apache.poi.ss.formula.functions.Function;
+import org.apache.poi.ss.formula.functions.NotImplementedFunction;
 import org.apache.poi.ss.formula.functions.Sumifs;
 import org.apache.poi.ss.formula.udf.UDFFinder;
 import org.apache.poi.ss.formula.OperationEvaluationContext;
@@ -175,4 +180,55 @@ public final class AnalysisToolPak imple
         FreeRefFunction func = pFunc == null ? new NotImplemented(functionName) : pFunc;
         m.put(functionName, func);
     }
+
+    public static boolean isATPFunction(String name){
+        AnalysisToolPak inst = (AnalysisToolPak)instance;
+        return inst._functionsByName.containsKey(name);
+    }
+
+    /**
+     * Returns an array of function names implemented by POI.
+     *
+     * @return an array of supported functions
+     * @since 3.8 beta6
+     */
+    public static String[] getSupportedFunctionNames(){
+        AnalysisToolPak inst = (AnalysisToolPak)instance;
+        ArrayList<String> lst = new ArrayList<String>();
+        for(String name : inst._functionsByName.keySet()){
+            FreeRefFunction func = inst._functionsByName.get(name);
+            if(func != null && !(func instanceof NotImplemented)){
+                lst.add(name);
+            }
+        }
+        return lst.toArray(new String[lst.size()]);
+    }
+
+    /**
+     * Register a ATP function in runtime.
+     *
+     * @param name  the function name
+     * @param func  the functoin to register
+     * @throws IllegalArgumentException if the function is unknown or already  registered.
+     * @since 3.8 beta6
+     */
+   public static void registerFunction(String name, FreeRefFunction func){
+        AnalysisToolPak inst = (AnalysisToolPak)instance;
+        if(!isATPFunction(name)) {
+            FunctionMetadata metaData = FunctionMetadataRegistry.getFunctionByName(name);
+            if(metaData != null) {
+                throw new IllegalArgumentException(name + " is a built-in Excel function. " +
+                        "Use FunctoinEval.registerFunction(String name, Function func) instead.");
+            } else {
+                throw new IllegalArgumentException(name + " is not a function from the Excel Analysis Toolpack.");
+            }
+        }
+        FreeRefFunction f = inst.findFunction(name);
+        if(f != null && !(f instanceof NotImplemented)) {
+            throw new IllegalArgumentException("POI already implememts " + name +
+                    ". You cannot override POI's implementations of Excel functions");
+        }
+
+        inst._functionsByName.put(name, func);
+    }
 }

Modified: poi/trunk/src/java/org/apache/poi/ss/formula/eval/FunctionEval.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/ss/formula/eval/FunctionEval.java?rev=1291677&r1=1291676&r2=1291677&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/ss/formula/eval/FunctionEval.java (original)
+++ poi/trunk/src/java/org/apache/poi/ss/formula/eval/FunctionEval.java Tue Feb 21 09:43:01 2012
@@ -17,10 +17,13 @@
 
 package org.apache.poi.ss.formula.eval;
 
+import org.apache.poi.ss.formula.atp.AnalysisToolPak;
 import org.apache.poi.ss.formula.function.FunctionMetadata;
 import org.apache.poi.ss.formula.function.FunctionMetadataRegistry;
 import org.apache.poi.ss.formula.functions.*;
 
+import java.util.ArrayList;
+
 /**
  * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
  */
@@ -255,4 +258,50 @@ public final class FunctionEval {
 		}
 		return result;
 	}
+
+    /**
+     * Register a new function in runtime.
+     *
+     * @param name  the function name
+     * @param func  the functoin to register
+     * @throws IllegalArgumentException if the function is unknown or already  registered.
+     * @since 3.8 beta6
+     */
+    public static void registerFunction(String name, Function func){
+        FunctionMetadata metaData = FunctionMetadataRegistry.getFunctionByName(name);
+        if(metaData == null) {
+            if(AnalysisToolPak.isATPFunction(name)) {
+                throw new IllegalArgumentException(name + " is a function from the Excel Analysis Toolpack. " +
+                        "Use AnalysisToolpack.registerFunction(String name, FreeRefFunction func) instead.");
+            } else {
+                throw new IllegalArgumentException("Unknown function: " + name);
+            }
+        }
+
+        int idx = metaData.getIndex();
+        if(functions[idx] instanceof NotImplementedFunction) {
+            functions[idx] = func;
+        } else {
+            throw new IllegalArgumentException("POI already implememts " + name +
+                    ". You cannot override POI's implementations of Excel functions");
+        }
+    }
+
+    /**
+     * Returns an array of function names implemented by POI.
+     *
+     * @return an array of supported functions
+     * @since 3.8 beta6
+     */
+    public static String[] getSupportedFunctionNames(){
+        ArrayList<String>  lst = new ArrayList<String>();
+        for(int i = 0; i < functions.length; i++){
+            Function func = functions[i];
+            if(func != null && !(func instanceof NotImplementedFunction)){
+                FunctionMetadata metaData = FunctionMetadataRegistry.getFunctionByIndex(i);
+                lst.add(metaData.getName());
+            }
+        }
+        return lst.toArray(new String[lst.size()]);
+    }
 }

Added: poi/trunk/src/testcases/org/apache/poi/ss/formula/TestFunctionRegistry.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/ss/formula/TestFunctionRegistry.java?rev=1291677&view=auto
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/ss/formula/TestFunctionRegistry.java (added)
+++ poi/trunk/src/testcases/org/apache/poi/ss/formula/TestFunctionRegistry.java Tue Feb 21 09:43:01 2012
@@ -0,0 +1,136 @@
+/*
+ *  ====================================================================
+ *    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.ss.formula;
+
+import junit.framework.TestCase;
+import org.apache.poi.hssf.usermodel.*;
+import org.apache.poi.ss.formula.atp.AnalysisToolPak;
+import org.apache.poi.ss.formula.eval.ErrorEval;
+import org.apache.poi.ss.formula.eval.FunctionEval;
+import org.apache.poi.ss.formula.eval.NotImplementedException;
+import org.apache.poi.ss.formula.eval.ValueEval;
+import org.apache.poi.ss.formula.functions.FreeRefFunction;
+import org.apache.poi.ss.formula.functions.Function;
+import org.apache.poi.ss.usermodel.CellValue;
+
+/**
+ *
+ * @author Yegor Kozlov
+ */
+public class TestFunctionRegistry extends TestCase {
+
+	public void testRegisterInRuntime() {
+		HSSFWorkbook wb = new HSSFWorkbook();
+		HSSFSheet sheet = wb.createSheet("Sheet1");
+		HSSFRow row = sheet.createRow(0);
+        HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
+
+		HSSFCell cellA = row.createCell(0);
+		cellA.setCellFormula("FISHER(A5)");
+		CellValue cv;
+		try {
+			cv = fe.evaluate(cellA);
+            fail("expectecd exception");
+		} catch (NotImplementedException e) {
+			;
+		}
+
+        FunctionEval.registerFunction("FISHER", new Function() {
+            public ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+                return ErrorEval.NA;
+            }
+        });
+
+        cv = fe.evaluate(cellA);
+        assertEquals(ErrorEval.NA.getErrorCode(), cv.getErrorValue());
+
+        HSSFCell cellB = row.createCell(1);
+        cellB.setCellFormula("CUBEMEMBERPROPERTY(A5)");
+        try {
+            cv = fe.evaluate(cellB);
+            fail("expectecd exception");
+        } catch (NotImplementedException e) {
+            ;
+        }
+
+        AnalysisToolPak.registerFunction("CUBEMEMBERPROPERTY", new FreeRefFunction() {
+            public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) {
+                return ErrorEval.NUM_ERROR;
+            }
+        });
+
+        cv = fe.evaluate(cellB);
+        assertEquals(ErrorEval.NUM_ERROR.getErrorCode(), cv.getErrorValue());
+	}
+
+    public void testExceptions() {
+        Function func = new Function() {
+            public ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+                return ErrorEval.NA;
+            }
+        };
+        try {
+            FunctionEval.registerFunction("SUM", func);
+            fail("expectecd exception");
+        } catch (IllegalArgumentException e){
+            assertEquals("POI already implememts SUM" +
+                    ". You cannot override POI's implementations of Excel functions", e.getMessage());
+        }
+        try {
+            FunctionEval.registerFunction("SUMXXX", func);
+            fail("expectecd exception");
+        } catch (IllegalArgumentException e){
+            assertEquals("Unknown function: SUMXXX", e.getMessage());
+        }
+        try {
+            FunctionEval.registerFunction("ISODD", func);
+            fail("expectecd exception");
+        } catch (IllegalArgumentException e){
+            assertEquals("ISODD is a function from the Excel Analysis Toolpack. " +
+                    "Use AnalysisToolpack.registerFunction(String name, FreeRefFunction func) instead.", e.getMessage());
+        }
+
+        FreeRefFunction atpFunc = new FreeRefFunction() {
+            public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) {
+                return ErrorEval.NUM_ERROR;
+            }
+        };
+        try {
+            AnalysisToolPak.registerFunction("ISODD", atpFunc);
+            fail("expectecd exception");
+        } catch (IllegalArgumentException e){
+            assertEquals("POI already implememts ISODD" +
+                    ". You cannot override POI's implementations of Excel functions", e.getMessage());
+        }
+        try {
+            AnalysisToolPak.registerFunction("ISODDXXX", atpFunc);
+            fail("expectecd exception");
+        } catch (IllegalArgumentException e){
+            assertEquals("ISODDXXX is not a function from the Excel Analysis Toolpack.", e.getMessage());
+        }
+        try {
+            AnalysisToolPak.registerFunction("SUM", atpFunc);
+            fail("expectecd exception");
+        } catch (IllegalArgumentException e){
+            assertEquals("SUM is a built-in Excel function. " +
+                    "Use FunctoinEval.registerFunction(String name, Function func) instead.", e.getMessage());
+        }
+    }
+}



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org