    1   /*
    2    * Copyright 1999-2004 The Apache Software Foundation
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *     http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  package org.apache.commons.jxpath;
    17
    18  import java.util.ArrayList;
    19  import java.util.HashMap;
    20  import java.util.Iterator;
    21  import java.util.List;
    22  import java.util.Set;
    23
    24  /***
    25   * An object that aggregates Functions objects into a group Functions object.
    26   * Since JXPathContext can only register a single Functions object,
    27   * FunctionLibrary should always be used to group all Functions objects
    28   * that need to be registered.
    29   *
    30   * @author Dmitri Plotnikov
    31   * @version $Revision: 1.5 $ $Date: 2004/02/29 14:17:42 $
    32   */
    33  public class FunctionLibrary implements Functions {
    34      private List allFunctions = new ArrayList();
    35      private HashMap byNamespace = null;
    36
    37      /***
    38       * Add functions to the library
    39       */
    40      public void addFunctions(Functions functions) {
    41          allFunctions.add(functions);
    42          byNamespace = null;
    43      }
    44
    45      /***
    46       * Remove functions from the library.
    47       */
    48      public void removeFunctions(Functions functions) {
    49          allFunctions.remove(functions);
    50          byNamespace = null;
    51      }
    52
    53      /***
    54       * Returns a set containing all namespaces used by the aggregated
    55       * Functions.
    56       */
    57      public Set getUsedNamespaces() {
    58          if (byNamespace == null) {
    59              prepareCache();
    60          }
    61          return byNamespace.keySet();
    62      }
    63
    64      /***
    65       * Returns a Function, if any, for the specified namespace,
    66       * name and parameter types.
    67       */
    68      public Function getFunction(
    69          String namespace,
    70          String name,
    71          Object[] parameters)
    72      {
    73          if (byNamespace == null) {
    74              prepareCache();
    75          }
    76          Object candidates = byNamespace.get(namespace);
    77          if (candidates instanceof Functions) {
    78              return ((Functions) candidates).getFunction(
    79                  namespace,
    80                  name,
    81                  parameters);
    82          }
    83          else if (candidates instanceof List) {
    84              List list = (List) candidates;
    85              int count = list.size();
    86              for (int i = 0; i < count; i++) {
    87                  Function function =
    88                      ((Functions) list.get(i)).getFunction(
    89                          namespace,
    90                          name,
    91                          parameters);
    92                  if (function != null) {
    93                      return function;
    94                  }
    95              }
    96          }
    97          return null;
    98      }
    99
    100     private void prepareCache() {
    101         byNamespace = new HashMap();
    102         int count = allFunctions.size();
    103         for (int i = 0; i < count; i++) {
    104             Functions funcs = (Functions) allFunctions.get(i);
    105             Set namespaces = funcs.getUsedNamespaces();
    106             for (Iterator it = namespaces.iterator(); it.hasNext();) {
    107                 String ns = (String) it.next();
    108                 Object candidates = byNamespace.get(ns);
    109                 if (candidates == null) {
    110                     byNamespace.put(ns, funcs);
    111                 }
    112                 else if (candidates instanceof Functions) {
    113                     List lst = new ArrayList();
    114                     lst.add(candidates);
    115                     lst.add(funcs);
    116                     byNamespace.put(ns, lst);
    117                 }
    118                 else {
    119                     ((List) candidates).add(funcs);
    120                 }
    121             }
    122         }
    123     }
    124 }