KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mmbase > util > functions > FunctionSets


1 /*
2
3 This software is OSI Certified Open Source Software.
4 OSI Certified is a certification mark of the Open Source Initiative.
5
6 The license (Mozilla version 1.0) can be read at the MMBase site.
7 See http://www.MMBase.org/license
8
9 */

10 package org.mmbase.util.functions;
11
12 import org.mmbase.util.logging.Logger;
13 import org.mmbase.util.logging.Logging;
14 import org.mmbase.util.xml.DocumentReader;
15 import org.mmbase.util.*;
16 import org.mmbase.module.core.*;
17
18 import java.io.*;
19 import java.util.*;
20 import org.xml.sax.InputSource JavaDoc;
21 import org.w3c.dom.*;
22 import java.net.*;
23
24
25
26 /**
27  * A utility class for maintaining and querying functionsets.
28  * A set function belongs to a certain namespace of functions ('sets'), and therefore is identified by
29  * two strings: The name of the 'set' and the name of the function.
30  * <br />
31  * Function sets can be defined in the functions/functionsets.xml configuration file.
32  * <br />
33  * This class implements a number of static methods for maintaining {@link FunctionSet} objects,
34  * and filling these with {@link FunctionSet} objects that match the namespace.
35  * It also implements a {@link #getFunction} method for obtaining a function from such a set.
36  *
37  * @author Dani&euml;l Ockeloen
38  * @author Michiel Meeuwissen
39  * @since MMBase-1.8
40  * @version $Id: FunctionSets.java,v 1.22.2.2 2006/10/26 11:41:56 michiel Exp $
41  */

42 public class FunctionSets {
43
44     public static final String JavaDoc DTD_FUNCTIONSET_1_0 = "functionset_1_0.dtd";
45     public static final String JavaDoc DTD_FUNCTIONSETS_1_0 = "functionsets_1_0.dtd";
46
47     public static final String JavaDoc PUBLIC_ID_FUNCTIONSET_1_0 = "-//MMBase//DTD functionset config 1.0//EN";
48     public static final String JavaDoc PUBLIC_ID_FUNCTIONSETS_1_0 = "-//MMBase//DTD functionsets config 1.0//EN";
49
50     private static final Logger log = Logging.getLoggerInstance(FunctionSets.class);
51
52     private static final Map functionSets = new HashMap();
53
54     static {
55         XMLEntityResolver.registerPublicID(PUBLIC_ID_FUNCTIONSET_1_0, DTD_FUNCTIONSET_1_0, FunctionSets.class);
56         XMLEntityResolver.registerPublicID(PUBLIC_ID_FUNCTIONSETS_1_0, DTD_FUNCTIONSETS_1_0, FunctionSets.class);
57     }
58
59     /**
60      * Returns the {@link Function} with the given function name, and which exists in the set with the given set name.
61      * If this is the first call, or if the set does not exist in the cache, the cache
62      * is refreshed by reading the functionset.xml configuration file.
63      * @param setName the name of the function set
64      * @param functionName the name of the function
65      * @return the {@link Function}, or <code>nulll</code> if either the fucntion or set is not defined
66      */

67     public static Function getFunction(String JavaDoc setName, String JavaDoc functionName) {
68         FunctionSet set = getFunctionSet(setName);
69         if (set != null) {
70             Function fun = set.getFunction(functionName);
71             if (fun != null) {
72                 return fun;
73             } else {
74                 log.warn("No function with name : " + functionName + " in set : " + setName + ", functions available: " + set);
75             }
76         } else {
77             log.warn("No functionset with name : " + setName);
78         }
79         return null;
80     }
81
82     static {
83         ResourceLoader functionLoader = ResourceLoader.getConfigurationRoot().getChildResourceLoader("functions");
84         // read the XML
85
try {
86             ResourceWatcher watcher = new ResourceWatcher(functionLoader) {
87                     public void onChange(String JavaDoc resource) {
88                         functionSets.clear();
89                         clear();
90                         add(resource);
91                         readSets(this);
92                     }
93                 };
94             watcher.start();
95             watcher.onChange("functionsets.xml");
96         } catch (Throwable JavaDoc t) {
97             log.error(t.getClass().getName() + ": " + Logging.stackTrace(t));
98         }
99
100     }
101
102     /**
103      * Returns the {@link FunctionSet} with the given set name.
104      * If this is the first call, or if the set does not exist in the cache, the cache
105      * is refreshed by reading the functionset.xml configuration file.
106      * configuration file.
107      * @param setName the name of the function set
108      * @return the {@link FunctionSet}, or <code>null</code> if the set is not defined
109      */

110     public static FunctionSet getFunctionSet(String JavaDoc setName) {
111         return (FunctionSet)functionSets.get(setName);
112     }
113
114     /**
115      * Reads the current function set from the functionsets.xml configuration file.
116      * The read sets are added to the functionset cache.
117      * @todo It makes FunctionSet's now using a sub-XML. It would be possible to create a complete function-set by reflection.
118      */

119
120     private static void readSets(ResourceWatcher watcher) {
121
122         List resources = watcher.getResourceLoader().getResourceList("functionsets.xml");
123         log.service("Using " + resources);
124         ListIterator i = resources.listIterator();
125         while (i.hasNext()) i.next();
126         while (i.hasPrevious()) {
127             try {
128                 URL u = (URL) i.previous();
129                 log.service("Reading " + u);
130                 URLConnection con = u.openConnection();
131                 if (con.getDoInput()) {
132                     InputSource JavaDoc source = new InputSource JavaDoc(con.getInputStream());
133                     DocumentReader reader = new DocumentReader(source, FunctionSets.class);
134
135                     for(Iterator ns = reader.getChildElements("functionsets", "functionset"); ns.hasNext(); ) {
136                         Element n = (Element)ns.next();
137
138                         String JavaDoc setName = n.getAttribute("name");
139                         if (functionSets.containsKey(setName)) {
140                             log.warn("The function-set '" + setName + "' did exist already");
141                         }
142                         String JavaDoc setResource = n.getAttribute("resource");
143                         if (setResource.equals("")) setResource = n.getAttribute("file"); // deprecated, it's not necessarily a file
144
watcher.add(setResource);
145                         decodeFunctionSet(watcher.getResourceLoader(), setResource, setName);
146                     }
147                 }
148             } catch (Exception JavaDoc e) {
149                 log.error(e);
150             }
151         }
152     }
153
154     /**
155      * Reads a 'sub' xml (a functionset XML) referred to by functionsets.xml.
156      * The read set is added to the functionset cache.
157      * @param
158      * @param
159      */

160     private static void decodeFunctionSet(ResourceLoader loader, String JavaDoc setResource, String JavaDoc setName) throws IOException {
161         DocumentReader reader = new DocumentReader(loader.getInputSource(setResource), FunctionSets.class);
162
163         String JavaDoc setDescription = reader.getElementValue("functionset.description");
164
165         FunctionSet functionSet = new FunctionSet(setName, setDescription);
166         functionSets.put(setName, functionSet);
167
168         for (Iterator functionElements = reader.getChildElements("functionset", "function"); functionElements.hasNext();) {
169             Element element = (Element)functionElements.next();
170             String JavaDoc functionName = reader.getElementAttributeValue(element,"name");
171             if (functionName != null) {
172
173                 Element a = reader.getElementByPath(element, "function.type");
174
175                 String JavaDoc type = reader.getElementValue(a); // 'class' or 'instance'
176

177                 a = reader.getElementByPath(element, "function.description");
178                 String JavaDoc description = reader.getElementValue(a);
179
180                 a = reader.getElementByPath(element, "function.class");
181                 String JavaDoc className = reader.getElementValue(a);
182
183                 a = reader.getElementByPath(element, "function.method");
184                 String JavaDoc methodName = reader.getElementValue(a);
185
186                 // read the return types and values
187
a = reader.getElementByPath(element, "function.return");
188                 ReturnType returnType = null;
189         if (a != null) {
190                     String JavaDoc returnTypeClassName = reader.getElementAttributeValue(a, "type");
191                     if (returnTypeClassName != null) {
192                         try {
193                             Class JavaDoc returnTypeClass = getClassFromName(returnTypeClassName);
194                             returnType = new ReturnType(returnTypeClass, "");
195                         } catch (Exception JavaDoc e) {
196                             log.warn("Cannot determine return type : " + returnTypeClassName + ", will auto-detect");
197                         }
198                     }
199                 }
200
201
202                 /* obtaining field definitions for a result Node... useful ??
203
204                 for (Enumeration n2 = reader.getChildElements(a, "field"); n2.hasMoreElements();) {
205                     Element return_element = (Element)n2.nextElement();
206                     String returnFieldName = reader.getElementAttributeValue(return_element, "name");
207                     String returnFieldValueType = reader.getElementAttributeValue(return_element, "type");
208                     String returnFieldDescription = reader.getElementAttributeValue(return_element, "description");
209                     // not implemented (yet) :
210                     // FunctionReturnValue r=new FunctionReturnValue(returnname,returnvaluetype);
211                     // fun.addReturnValue(returnname,r);
212                     // r.setDescription(description);
213                 }
214                 */

215
216                 // read the parameters
217
List parameterList = new ArrayList();
218                 for (Iterator parameterElements = reader.getChildElements(element,"param"); parameterElements.hasNext();) {
219                     Element parameterElement = (Element)parameterElements.next();
220                     String JavaDoc parameterName = reader.getElementAttributeValue(parameterElement, "name");
221                     String JavaDoc parameterType = reader.getElementAttributeValue(parameterElement, "type");
222                     String JavaDoc required = reader.getElementAttributeValue(parameterElement, "required");
223                     description = reader.getElementAttributeValue(parameterElement, "description");
224
225                     Parameter parameter = null;
226
227                     Class JavaDoc parameterClass = getClassFromName(parameterType);
228                     parameter = new Parameter(parameterName, parameterClass);
229                     parameter.dataType.setRequired("true".equals(required));
230
231                     if (parameterClass.isPrimitive() && parameter.getDefaultValue() == null && ! parameter.isRequired()) {
232                         // that would give enigmatic IllegalArgumentExceptions, so fix that.
233
parameter.setDefaultValue(Casting.toType(parameterClass, new Integer JavaDoc(-1)));
234                         log.info("Primitive parameter '" + parameterName + "' had default value null, which is impossible for primitive types. Setting to " + parameter.getDefaultValue());
235                     }
236                     // check for a default value
237
org.w3c.dom.Node JavaDoc n3 = parameterElement.getFirstChild();
238                     if (n3 != null) {
239                         parameter.setDefaultValue(parameter.autoCast(n3.getNodeValue()));
240                     }
241                     parameterList.add(parameter);
242
243                 }
244
245                 Parameter[] parameters = (Parameter[]) parameterList.toArray(new Parameter[0]);
246
247                 try {
248                     SetFunction fun = new SetFunction(functionName, parameters, returnType, className, methodName);
249                     fun.setType(type);
250                     fun.setDescription(description);
251                     functionSet.addFunction(fun);
252                 } catch (Exception JavaDoc e) {
253                     log.error(e);
254                     log.error(Logging.stackTrace(e));
255                     log.error(Logging.stackTrace(e.getCause()));
256                 }
257             }
258         }
259     }
260
261     /**
262      * Tries to determine the correct class from a given classname.
263      * Classnames that are not fully expanded are expanded to the java.lang package.
264      */

265     private static Class JavaDoc getClassFromName(String JavaDoc className) {
266         String JavaDoc fullClassName = className;
267         boolean fullyQualified = className.indexOf('.') > -1;
268         if (!fullyQualified) {
269             if (className.equals("int")) { // needed?
270
return int.class;
271             } else if (className.equals("NodeList")) {
272                 return org.mmbase.bridge.NodeList.class;
273             } else if (className.equals("Node")) {
274                 return org.mmbase.bridge.Node.class;
275             }
276             fullClassName = "java.lang." + fullClassName;
277         }
278         try {
279             return Class.forName(fullClassName);
280         } catch (ClassNotFoundException JavaDoc cne) {
281             log.warn("Cannot determine parameter type : '" + className + "' (expanded to: '" + fullClassName + "'), using Object as type instead.");
282             return Object JavaDoc.class;
283         }
284     }
285
286 }
287
Popular Tags