001    /**
002     * =========================================
003     * LibFormula : a free Java formula library
004     * =========================================
005     *
006     * Project Info:  http://reporting.pentaho.org/libformula/
007     *
008     * (C) Copyright 2006-2007, by Pentaho Corporation and Contributors.
009     *
010     * This library is free software; you can redistribute it and/or modify it under the terms
011     * of the GNU Lesser General Public License as published by the Free Software Foundation;
012     * either version 2.1 of the License, or (at your option) any later version.
013     *
014     * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
015     * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016     * See the GNU Lesser General Public License for more details.
017     *
018     * You should have received a copy of the GNU Lesser General Public License along with this
019     * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
020     * Boston, MA 02111-1307, USA.
021     *
022     * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
023     * in the United States and other countries.]
024     *
025     *
026     * ------------
027     * $Id: DefaultFunctionRegistry.java 3325 2007-09-12 23:57:55Z tmorgner $
028     * ------------
029     * (C) Copyright 2006-2007, by Pentaho Corporation.
030     */
031    package org.jfree.formula.function;
032    
033    import java.util.ArrayList;
034    import java.util.HashMap;
035    import java.util.HashSet;
036    import java.util.Iterator;
037    
038    import org.jfree.util.Configuration;
039    import org.jfree.util.HashNMap;
040    import org.jfree.util.Log;
041    import org.jfree.util.ObjectUtilities;
042    
043    /**
044     * Creation-Date: 02.11.2006, 12:48:32
045     *
046     * @author Thomas Morgner
047     */
048    public class DefaultFunctionRegistry implements FunctionRegistry
049    {
050      private static final String FUNCTIONS_PREFIX = "org.jfree.formula.functions.";
051      private static final String[] EMPTY_ARRAY = new String[0];
052      private static final FunctionCategory[] EMPTY_CATEGORIES = new FunctionCategory[0];
053    
054      private FunctionCategory[] categories;
055      private HashNMap categoryFunctions;
056      private HashMap functions;
057      private HashMap functionMetaData;
058      private HashMap cachedFunctions;
059    
060      public DefaultFunctionRegistry()
061      {
062        cachedFunctions = new HashMap();
063        categoryFunctions = new HashNMap();
064        functionMetaData = new HashMap();
065        functions = new HashMap();
066        categories = EMPTY_CATEGORIES;
067      }
068    
069      public FunctionCategory[] getCategories()
070      {
071        return (FunctionCategory[]) categories.clone();
072      }
073    
074      public Function[] getFunctions()
075      {
076        final String[] fnNames = getFunctionNames();
077        final ArrayList functions = new ArrayList(fnNames.length);
078        for (int i = 0; i < fnNames.length; i++)
079        {
080          final String aName = fnNames[i];
081          final Function function = createFunction(aName);
082          if (function == null)
083          {
084            Log.debug ("There is no such function: " + aName);
085          }
086          else
087          {
088            functions.add(function);
089          }
090        }
091        return (Function[]) functions.toArray(new Function[functions.size()]);
092      }
093    
094      public String[] getFunctionNames()
095      {
096        return (String[]) functions.keySet().toArray(new String[functions.size()]);
097      }
098    
099      public String[] getFunctionNamesByCategory(final FunctionCategory category)
100      {
101        return (String[]) categoryFunctions.toArray(category, EMPTY_ARRAY);
102      }
103    
104      public Function[] getFunctionsByCategory(final FunctionCategory category)
105      {
106        final String[] fnNames = (String[]) categoryFunctions.toArray(category, EMPTY_ARRAY);
107        final ArrayList functions = new ArrayList(fnNames.length);
108        for (int i = 0; i < fnNames.length; i++)
109        {
110          final String aName = fnNames[i];
111          final Function function = createFunction(aName);
112          if (function != null)
113          {
114            functions.add(function);
115          }
116        }
117        return (Function[]) functions.toArray(new Function[functions.size()]);
118      }
119    
120      public Function createFunction(final String name)
121      {
122        if (name == null)
123        {
124          throw new NullPointerException();
125        }
126        final String functionClass = (String) functions.get(name.toUpperCase());
127        final Class cachedClass = (Class) cachedFunctions.get(functionClass);
128        if (cachedClass != null)
129        {
130          try
131          {
132            return (Function) cachedClass.newInstance();
133          }
134          catch (Exception e)
135          {
136            return null;
137          }
138        }
139    
140        final Function function = (Function) ObjectUtilities.loadAndInstantiate
141            (functionClass, DefaultFunctionRegistry.class, Function.class);
142        if (function == null)
143        {
144          Log.debug ("There is no such function: " + name);
145        }
146        else
147        {
148          cachedFunctions.put(functionClass, function.getClass());
149        }
150        return function;
151      }
152    
153      public FunctionDescription getMetaData(final String name)
154      {
155        if (name == null)
156        {
157          throw new NullPointerException();
158        }
159        return (FunctionDescription) functionMetaData.get(name.toUpperCase());
160      }
161    
162      public void initialize(final Configuration configuration)
163      {
164        final Iterator functionKeys =
165            configuration.findPropertyKeys(FUNCTIONS_PREFIX);
166        final HashSet categories = new HashSet();
167    
168    
169        while (functionKeys.hasNext())
170        {
171          final String classKey = (String) functionKeys.next();
172          if (classKey.endsWith(".class") == false)
173          {
174            continue;
175          }
176    
177          final String className = configuration.getConfigProperty(classKey);
178          if (className.length() == 0)
179          {
180            continue;
181          }
182          final Object fn = ObjectUtilities.loadAndInstantiate
183              (className, DefaultFunctionRegistry.class, Function.class);
184          if (fn instanceof Function == false)
185          {
186            continue;
187          }
188    
189          final Function function = (Function) fn;
190    
191          final int endIndex = classKey.length() - ".class".length();
192          final String descrKey = classKey.substring(0, endIndex) + ".description";
193          final String descrClassName = configuration.getConfigProperty(descrKey);
194          final Object descr = ObjectUtilities.loadAndInstantiate
195              (descrClassName, DefaultFunctionRegistry.class, FunctionDescription.class);
196    
197          final FunctionDescription description;
198          if (descr instanceof FunctionDescription == false)
199          {
200            description = new DefaultFunctionDescription(function.getCanonicalName());
201          }
202          else
203          {
204            description = (FunctionDescription) descr;
205          }
206    
207          final FunctionCategory cat = description.getCategory();
208          categoryFunctions.add(cat, function.getCanonicalName());
209          functionMetaData.put (function.getCanonicalName(), description);
210          functions.put(function.getCanonicalName(), className);
211          categories.add(cat);
212        }
213    
214        this.categories = (FunctionCategory[]) categories.toArray(new FunctionCategory[categories.size()]);
215      }
216    
217    }