/* * FormulaFunctionList.java * * Created on April 29, 2006, 9:33 PM * * Copyright 2006 Lee Lofgern and Accounting Enhancements Inc Licensed 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 com.accountingenhancements.formula; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; /** *FormulaFunctionList is used to hand various programmer defined functions to the various Formula solve(...) methods, such as FormulaVariable.solve(...). For a FormulaVariable of TYPE_FUNCTION, the solve method will call the getFunction(FormulaVariable functionVariable) method to instantiate correct Function.
*Example: formulaVariable=new FormulaFunction("","IIF(9<8,7,6)",0,true); getFunction(formulaVariable); will return a ((FormulaFunction)new FormulaFunction_IIF(formulaVariable)) through the use of reflection.
*When creating a function, it needs to extend FormulaFunction. Take a look at FormulaFunction_Left or any of the other built-in functions for examples. Most of these functions override the solve(...) method, however, FormulaFunction_IIF overrides the function(...) method. It is better to override the solve() method in case more function(...) methods are added in the future (All function(...) methods from the underlying FormulaFunction call solve(...) to retrieve the result).
* Note: When creating a new function, the public static getName() and public FormulaVariable solve(...) methods must be overridden!!!
* The getRequiredSupportParameters(), getRequiredFormulaVariables(), getRequiredArguments(), and getRequiredArguments() are for allowing users to understand how to use the various formulas in a run-time formula creating environment. You should override the methods that apply to your situation. getRequiredArguments() is the most common one overriden. * @author Lee lofgren lofgren_opensource@accountingenhancements.com * @version 0.1009102006 */ public class FormulaFunctionList { HashMap> functionList = new HashMap>(); /** Creates a new instance of FormulaFunctionList. *The following Function classes are automatically added to the list:
*FormulaFunction_IIF, FormulaFunction_LCase, FormulaFunction_Left, FormulaFunction_Ren, FormulaFunction_Mid, FormulaFunction_Right, and , FormulaFunction_UCase.
*/ public FormulaFunctionList() { addFunction(FormulaFunction_DateAdd.class); addFunction(FormulaFunction_DatePart.class); addFunction(FormulaFunction_IIF.class); addFunction(FormulaFunction_LCase.class); addFunction(FormulaFunction_Left.class); addFunction(FormulaFunction_Len.class); addFunction(FormulaFunction_Mid.class); addFunction(FormulaFunction_Right.class); addFunction(FormulaFunction_UCase.class); } /** *@param functionClass a function.class that extends FormulaFunction that is to be added to the list. The function name will be tracked as upper case. The name is retrieved through the getName() function so make this has been overriden from the underlying class. FormulaFunction.getName() returns "" and won't be added. */ public void addFunction(Class functionClass){ String name=""; try { name=(String)functionClass.getMethod("getName").invoke(functionClass); } catch (IllegalArgumentException ex) { } catch (SecurityException ex) { } catch (IllegalAccessException ex) { } catch (InvocationTargetException ex) { } catch (NoSuchMethodException ex) {} if(name!=null&&name.length()!=0)functionList.put(name.toUpperCase(),functionClass); } /** *@param functionName a function name whose function is to be returned. The function name is converted to upper case for the search. If the function name contains the parentheses and arguments, these will be stripped off so handing IIF(9<8,5,4) to this routine will return the FormulaFunction_IIF class. */ public Class getFunctionClass(String functionName){ Class functionClass=null; int index; functionClass=functionList.get(functionName.toUpperCase()); if(functionClass==null){ //If not found function name may have parentheses so remove those and try again. index=functionName.indexOf('('); if(index>=0)functionName=functionName.substring(0,index); functionName=functionName.trim(); functionClass=functionList.get(functionName.toUpperCase()); } return functionClass; } /** *@param functionName a function name whose function is to be dropped from the list. The function name is converted to upper case. */ public void dropFunction(String functionName){ int index; if(functionList.containsKey(functionName.toUpperCase())==false){ index=functionName.indexOf('('); if(index>=0)functionName=functionName.substring(0,index); functionName=functionName.trim(); } functionList.remove(functionName.toUpperCase()); } /** *This method will instantiate and return the correct function based on the TYPE_FUNCTION FormulaVariable handed to this routine. *@param functionVariable A FormulaVariable of TYPE_FUNCTION. if the function name isn't found, or, if instantiating the class causes a ClassNotFoundException, IllegalAccessException, InstantiationExceptionSecurityException, NoSuchMethodException, or InvocationTargetException, a ClassNotFoundException will be thrown.
*Ex: functionVariable.getString()=="IIF(9<8,7,6)" will instantiate FormulaFunction_IIF using the ForulaFunction_IIF(FormulaVariable) constructor. */ public FormulaFunction getFunction(FormulaVariable functionVariable)throws java.lang.ClassNotFoundException{ FormulaFunction result=null; Class functionClass=null; java.lang.reflect.Constructor constructor; Object[] arguments=new Object[]{null}; Class[] formulaVariableClassArray = new Class[]{FormulaVariable.class}; if (functionVariable==null)throw new java.lang.ClassNotFoundException("FormulaVariable was null"); if (functionVariable.isNull())throw new java.lang.ClassNotFoundException("FormulaVariable contents were null"); if(functionVariable.getVariableType()!=FormulaVariable.TYPE_FUNCTION)throw new java.lang.ClassNotFoundException("FormulaVariable not TYPE_FUNCTION"); functionClass=getFunctionClass(functionVariable.getString()); if(functionClass==null)throw new java.lang.ClassNotFoundException("Class not found for: "+functionVariable.getString()); try { constructor=functionClass.getConstructor(formulaVariableClassArray); arguments[0]=(Object)functionVariable; result = (FormulaFunction)constructor.newInstance(arguments); } catch (java.lang.reflect.InvocationTargetException ex){throw new java.lang.ClassNotFoundException(ex.getMessage());} catch (java.lang.IllegalAccessException ex){throw new java.lang.ClassNotFoundException(ex.getMessage());} catch (java.lang.InstantiationException ex){throw new java.lang.ClassNotFoundException(ex.getMessage());} catch (SecurityException ex) {throw new java.lang.ClassNotFoundException(ex.getMessage());} catch (NoSuchMethodException ex) {throw new java.lang.ClassNotFoundException(ex.getMessage());} return result; } /** *@param function a function in String form. This creates a FormulaVariable from the supplied string with a default level of zero then calls the getFunction(FormulaVariable) method. */ public FormulaFunction getFunction(String function)throws java.lang.ClassNotFoundException{ FormulaVariable functionVar=new FormulaVariable("",function,0,true); return getFunction(functionVar); } /** *@param function a function in String form. This creates a FormulaVariable from the supplied string then calls the getFunction(FormulaVariable) method. *@param level is the level assigned to the newly created FormulaVariable. */ public FormulaFunction getFunction(String function, int level)throws java.lang.ClassNotFoundException{ FormulaVariable functionVar=new FormulaVariable("",function,level,true); return getFunction(functionVar); } }