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