View Javadoc
1   /*
2    * reserved comment block
3    * DO NOT REMOVE OR ALTER!
4    */
5   /*
6    * Copyright 2001-2004 The Apache Software Foundation.
7    *
8    * Licensed under the Apache License, Version 2.0 (the "License");
9    * you may not use this file except in compliance with the License.
10   * You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  /*
21   * $Id: FunctionAvailableCall.java,v 1.2.4.1 2005/09/01 15:30:25 pvedula Exp $
22   */
23  
24  package com.sun.org.apache.xalan.internal.xsltc.compiler;
25  
26  import java.lang.reflect.Method;
27  import java.lang.reflect.Modifier;
28  import java.util.Vector;
29  
30  import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
31  import com.sun.org.apache.bcel.internal.generic.PUSH;
32  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
33  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
34  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
35  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
36  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
37  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
38  import com.sun.org.apache.xalan.internal.utils.ObjectFactory;
39  
40  /**
41   * @author G. Todd Miller
42   * @author Santiago Pericas-Geertsen
43   */
44  final class FunctionAvailableCall extends FunctionCall {
45  
46      private Expression _arg;
47      private String     _nameOfFunct = null;
48      private String     _namespaceOfFunct = null;
49      private boolean    _isFunctionAvailable = false;
50  
51      /**
52       * Constructs a FunctionAvailableCall FunctionCall. Takes the
53       * function name qname, for example, 'function-available', and
54       * a list of arguments where the arguments must be instances of
55       * LiteralExpression.
56       */
57      public FunctionAvailableCall(QName fname, Vector arguments) {
58          super(fname, arguments);
59          _arg = (Expression)arguments.elementAt(0);
60          _type = null;
61  
62          if (_arg instanceof LiteralExpr) {
63              LiteralExpr arg = (LiteralExpr) _arg;
64              _namespaceOfFunct = arg.getNamespace();
65              _nameOfFunct = arg.getValue();
66  
67              if (!isInternalNamespace()) {
68                _isFunctionAvailable = hasMethods();
69              }
70          }
71      }
72  
73      /**
74       * Argument of function-available call must be literal, typecheck
75       * returns the type of function-available to be boolean.
76       */
77      public Type typeCheck(SymbolTable stable) throws TypeCheckError {
78          if (_type != null) {
79             return _type;
80          }
81          if (_arg instanceof LiteralExpr) {
82              return _type = Type.Boolean;
83          }
84          ErrorMsg err = new ErrorMsg(ErrorMsg.NEED_LITERAL_ERR,
85                          "function-available", this);
86          throw new TypeCheckError(err);
87      }
88  
89      /**
90       * Returns an object representing the compile-time evaluation
91       * of an expression. We are only using this for function-available
92       * and element-available at this time.
93       */
94      public Object evaluateAtCompileTime() {
95          return getResult() ? Boolean.TRUE : Boolean.FALSE;
96      }
97  
98      /**
99       * for external java functions only: reports on whether or not
100      * the specified method is found in the specifed class.
101      */
102     private boolean hasMethods() {
103         LiteralExpr arg = (LiteralExpr)_arg;
104 
105         // Get the class name from the namespace uri
106         String className = getClassNameFromUri(_namespaceOfFunct);
107 
108         // Get the method name from the argument to function-available
109         String methodName = null;
110         int colonIndex = _nameOfFunct.indexOf(":");
111         if (colonIndex > 0) {
112           String functionName = _nameOfFunct.substring(colonIndex+1);
113           int lastDotIndex = functionName.lastIndexOf('.');
114           if (lastDotIndex > 0) {
115             methodName = functionName.substring(lastDotIndex+1);
116             if (className != null && !className.equals(""))
117               className = className + "." + functionName.substring(0, lastDotIndex);
118             else
119               className = functionName.substring(0, lastDotIndex);
120           }
121           else
122             methodName = functionName;
123         }
124         else
125           methodName = _nameOfFunct;
126 
127         if (className == null || methodName == null) {
128             return false;
129         }
130 
131         // Replace the '-' characters in the method name
132         if (methodName.indexOf('-') > 0)
133           methodName = replaceDash(methodName);
134 
135         try {
136             final Class clazz = ObjectFactory.findProviderClass(className, true);
137 
138             if (clazz == null) {
139                 return false;
140             }
141 
142             final Method[] methods = clazz.getMethods();
143 
144             for (int i = 0; i < methods.length; i++) {
145                 final int mods = methods[i].getModifiers();
146 
147                 if (Modifier.isPublic(mods) && Modifier.isStatic(mods)
148                         && methods[i].getName().equals(methodName))
149                 {
150                     return true;
151                 }
152             }
153         }
154         catch (ClassNotFoundException e) {
155           return false;
156         }
157         return false;
158     }
159 
160     /**
161      * Reports on whether the function specified in the argument to
162      * xslt function 'function-available' was found.
163      */
164     public boolean getResult() {
165         if (_nameOfFunct == null) {
166             return false;
167         }
168 
169         if (isInternalNamespace()) {
170             final Parser parser = getParser();
171             _isFunctionAvailable =
172                 parser.functionSupported(Util.getLocalName(_nameOfFunct));
173         }
174         return _isFunctionAvailable;
175     }
176 
177     /**
178      * Return true if the namespace uri is null or it is the XSLTC translet uri.
179      */
180     private boolean isInternalNamespace() {
181         return (_namespaceOfFunct == null ||
182             _namespaceOfFunct.equals(EMPTYSTRING) ||
183             _namespaceOfFunct.equals(TRANSLET_URI));
184     }
185 
186     /**
187      * Calls to 'function-available' are resolved at compile time since
188      * the namespaces declared in the stylsheet are not available at run
189      * time. Consequently, arguments to this function must be literals.
190      */
191     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
192         final ConstantPoolGen cpg = classGen.getConstantPool();
193         methodGen.getInstructionList().append(new PUSH(cpg, getResult()));
194     }
195 
196 }