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