KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > mondrian > olap > fun > GlobalFunTable


1 /*
2 // $Id: //open/mondrian/src/main/mondrian/olap/fun/GlobalFunTable.java#6 $
3 // This software is subject to the terms of the Common Public License
4 // Agreement, available at the following URL:
5 // http://www.opensource.org/licenses/cpl.html.
6 // Copyright (C) 2006-2006 Julian Hyde and others
7 // All Rights Reserved.
8 // You must accept the terms of that agreement to use this software.
9 */

10 package mondrian.olap.fun;
11
12 import java.io.BufferedReader JavaDoc;
13 import java.io.IOException JavaDoc;
14 import java.io.InputStreamReader JavaDoc;
15 import java.net.URL JavaDoc;
16 import java.util.ArrayList JavaDoc;
17 import java.util.Enumeration JavaDoc;
18 import java.util.List JavaDoc;
19 import java.util.Set JavaDoc;
20 import java.util.Collection JavaDoc;
21 import java.util.HashSet JavaDoc;
22
23 import mondrian.olap.FunTable;
24 import mondrian.olap.Syntax;
25 import mondrian.olap.Util;
26 import mondrian.olap.type.Type;
27 import mondrian.resource.MondrianResource;
28 import mondrian.spi.UserDefinedFunction;
29
30 import org.apache.log4j.Logger;
31
32 /**
33  * Global function table contains builtin functions and global user-defined functions.
34  *
35  * @author Gang Chen
36  * @version $Id: //open/mondrian/src/main/mondrian/olap/fun/GlobalFunTable.java#6 $
37  */

38 public class GlobalFunTable extends FunTableImpl {
39
40     private static Logger logger = Logger.getLogger(GlobalFunTable.class);
41
42     private static GlobalFunTable instance = new GlobalFunTable();
43
44     public static GlobalFunTable instance() {
45         return instance;
46     }
47
48     private GlobalFunTable() {
49         super();
50         init();
51     }
52
53     protected void defineFunctions() {
54         final FunTable builtinFunTable = BuiltinFunTable.instance();
55         final List JavaDoc<String JavaDoc> reservedWords = builtinFunTable.getReservedWords();
56         for (String JavaDoc reservedWord : reservedWords) {
57             defineReserved(reservedWord);
58         }
59         final List JavaDoc<Resolver> resolvers = builtinFunTable.getResolvers();
60         for (Resolver resolver : resolvers) {
61             define(resolver);
62         }
63
64         for (String JavaDoc className : lookupUdfImplClasses()) {
65             defineUdf(className);
66         }
67     }
68
69
70     private Collection JavaDoc<String JavaDoc> lookupUdfImplClasses() {
71         ClassLoader JavaDoc cl = this.getClass().getClassLoader();
72         List JavaDoc<URL JavaDoc> serviceUrls = new ArrayList JavaDoc<URL JavaDoc>();
73         try {
74             Enumeration JavaDoc<URL JavaDoc> serviceEnum = cl.getResources("META-INF/services/mondrian.spi.UserDefinedFunction");
75             for (; serviceEnum.hasMoreElements();) {
76                 serviceUrls.add(serviceEnum.nextElement());
77             }
78         } catch (IOException JavaDoc e) {
79             logger.warn("Error while finding service files for user-defined functions", e);
80         }
81         Set JavaDoc<String JavaDoc> classNames = new HashSet JavaDoc<String JavaDoc>();
82         for (URL JavaDoc url : serviceUrls) {
83             BufferedReader JavaDoc reader = null;
84             try {
85                 reader =
86                     new BufferedReader JavaDoc(new InputStreamReader JavaDoc(url.openStream(),
87                         "UTF-8"));
88                 String JavaDoc line;
89                 while ((line = reader.readLine()) != null) {
90                     line = line.trim();
91                     if (line.length() > 0) {
92                         if (line.charAt(0) == '#') {
93                             continue;
94                         }
95                         int comment = line.indexOf('#');
96                         if (comment != -1) {
97                             line = line.substring(0, comment).trim();
98                         }
99                         classNames.add(line);
100                     }
101                 }
102             } catch (IOException JavaDoc e) {
103                 logger.warn("Error when loading service file '" + url + "'", e);
104             } finally {
105                 if (reader != null) {
106                     try {
107                         reader.close();
108                     } catch (IOException JavaDoc ignored) {
109                     }
110                 }
111             }
112         }
113         return classNames;
114     }
115
116     /**
117      * Defines a user-defined function in this table.
118      *
119      * <p>If the function is not valid, throws an error.
120      *
121      * @param className Name of the class which implements the function.
122      * The class must implement {@link mondrian.spi.UserDefinedFunction}
123      * (otherwise it is a user-error).
124      */

125     private void defineUdf(String JavaDoc className) {
126         // Load class.
127
final Class JavaDoc<?> udfClass;
128         try {
129             udfClass = Class.forName(className);
130         } catch (ClassNotFoundException JavaDoc e) {
131             throw MondrianResource.instance().UdfClassNotFound.ex("",className);
132         }
133
134         // Instantiate class with default constructor.
135
final UserDefinedFunction udf;
136         try {
137             udf = (UserDefinedFunction) udfClass.newInstance();
138         } catch (InstantiationException JavaDoc e) {
139             throw MondrianResource.instance().UdfClassWrongIface.ex("",
140                     className, UserDefinedFunction.class.getName());
141         } catch (IllegalAccessException JavaDoc e) {
142             throw MondrianResource.instance().UdfClassWrongIface.ex("",
143                     className, UserDefinedFunction.class.getName());
144         } catch (ClassCastException JavaDoc e) {
145             throw MondrianResource.instance().UdfClassWrongIface.ex("",
146                     className, UserDefinedFunction.class.getName());
147         }
148
149         // Validate function.
150
validateFunction(udf);
151
152         // Define function.
153
define(new UdfResolver(udf));
154     }
155
156     /**
157      * Throws an error if a user-defined function does not adhere to the
158      * API.
159      */

160     private void validateFunction(final UserDefinedFunction udf) {
161         // Check that the name is not null or empty.
162
final String JavaDoc udfName = udf.getName();
163         if (udfName == null || udfName.equals("")) {
164             throw Util.newInternal("User-defined function defined by class '" +
165                     udf.getClass() + "' has empty name");
166         }
167         // It's OK for the description to be null.
168
//final String description = udf.getDescription();
169

170         final Type[] parameterTypes = udf.getParameterTypes();
171         for (int i = 0; i < parameterTypes.length; i++) {
172             Type parameterType = parameterTypes[i];
173             if (parameterType == null) {
174                 throw Util.newInternal("Invalid user-defined function '" +
175                         udfName + "': parameter type #" + i +
176                         " is null");
177             }
178         }
179
180         // It's OK for the reserved words to be null or empty.
181
//final String[] reservedWords = udf.getReservedWords();
182

183         // Test that the function returns a sensible type when given the FORMAL
184
// types. It may still fail when we give it the ACTUAL types, but it's
185
// impossible to check that now.
186
final Type returnType = udf.getReturnType(parameterTypes);
187         if (returnType == null) {
188             throw Util.newInternal("Invalid user-defined function '" +
189                     udfName + "': return type is null");
190         }
191         final Syntax syntax = udf.getSyntax();
192         if (syntax == null) {
193             throw Util.newInternal("Invalid user-defined function '" +
194                     udfName + "': syntax is null");
195         }
196     }
197
198
199 }
200
201 // End GlobalFunTable.java
202
Popular Tags