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.xpath.internal.functions; 23 24 import com.sun.org.apache.xalan.internal.res.XSLMessages; 25 import com.sun.org.apache.xml.internal.utils.QName; 26 import com.sun.org.apache.xpath.internal.Expression; 27 import com.sun.org.apache.xpath.internal.ExpressionNode; 28 import com.sun.org.apache.xpath.internal.ExpressionOwner; 29 import com.sun.org.apache.xpath.internal.ExtensionsProvider; 30 import com.sun.org.apache.xpath.internal.XPathContext; 31 import com.sun.org.apache.xpath.internal.XPathVisitor; 32 import com.sun.org.apache.xpath.internal.objects.XNull; 33 import com.sun.org.apache.xpath.internal.objects.XObject; 34 import com.sun.org.apache.xpath.internal.res.XPATHErrorResources; 35 import com.sun.org.apache.xpath.internal.res.XPATHMessages; 36 import java.util.ArrayList; 37 import java.util.List; 38 39 /** 40 * An object of this class represents an extension call expression. When 41 * the expression executes, it calls ExtensionsTable#extFunction, and then 42 * converts the result to the appropriate XObject. 43 * @xsl.usage advanced 44 */ 45 public class FuncExtFunction extends Function 46 { 47 static final long serialVersionUID = 5196115554693708718L; 48 49 /** 50 * The namespace for the extension function, which should not normally 51 * be null or empty. 52 * @serial 53 */ 54 String m_namespace; 55 56 /** 57 * The local name of the extension. 58 * @serial 59 */ 60 String m_extensionName; 61 62 /** 63 * Unique method key, which is passed to ExtensionsTable#extFunction in 64 * order to allow caching of the method. 65 * @serial 66 */ 67 Object m_methodKey; 68 69 /** 70 * Array of static expressions which represent the parameters to the 71 * function. 72 * @serial 73 */ 74 List<Expression> m_argVec = new ArrayList<>(); 75 76 /** 77 * This function is used to fixup variables from QNames to stack frame 78 * indexes at stylesheet build time. 79 * @param vars List of QNames that correspond to variables. This list 80 * should be searched backwards for the first qualified name that 81 * corresponds to the variable reference qname. The position of the 82 * QName in the vector from the start of the vector will be its position 83 * in the stack frame (but variables above the globalsTop value will need 84 * to be offset to the current stack frame). 85 * NEEDSDOC @param globalsSize 86 */ 87 public void fixupVariables(List<QName> vars, int globalsSize) 88 { 89 90 if (null != m_argVec) 91 { 92 int nArgs = m_argVec.size(); 93 94 for (int i = 0; i < nArgs; i++) 95 { 96 Expression arg = m_argVec.get(i); 97 98 arg.fixupVariables(vars, globalsSize); 99 } 100 } 101 } 102 103 /** 104 * Return the namespace of the extension function. 105 * 106 * @return The namespace of the extension function. 107 */ 108 public String getNamespace() 109 { 110 return m_namespace; 111 } 112 113 /** 114 * Return the name of the extension function. 115 * 116 * @return The name of the extension function. 117 */ 118 public String getFunctionName() 119 { 120 return m_extensionName; 121 } 122 123 /** 124 * Return the method key of the extension function. 125 * 126 * @return The method key of the extension function. 127 */ 128 public Object getMethodKey() 129 { 130 return m_methodKey; 131 } 132 133 /** 134 * Return the nth argument passed to the extension function. 135 * 136 * @param n The argument number index. 137 * @return The Expression object at the given index. 138 */ 139 public Expression getArg(int n) { 140 if (n >= 0 && n < m_argVec.size()) 141 return m_argVec.get(n); 142 else 143 return null; 144 } 145 146 /** 147 * Return the number of arguments that were passed 148 * into this extension function. 149 * 150 * @return The number of arguments. 151 */ 152 public int getArgCount() { 153 return m_argVec.size(); 154 } 155 156 /** 157 * Create a new FuncExtFunction based on the qualified name of the extension, 158 * and a unique method key. 159 * 160 * @param namespace The namespace for the extension function, which should 161 * not normally be null or empty. 162 * @param extensionName The local name of the extension. 163 * @param methodKey Unique method key, which is passed to 164 * ExtensionsTable#extFunction in order to allow caching 165 * of the method. 166 */ 167 public FuncExtFunction(java.lang.String namespace, 168 java.lang.String extensionName, Object methodKey) 169 { 170 //try{throw new Exception("FuncExtFunction() " + namespace + " " + extensionName);} catch (Exception e){e.printStackTrace();} 171 m_namespace = namespace; 172 m_extensionName = extensionName; 173 m_methodKey = methodKey; 174 } 175 176 /** 177 * Execute the function. The function must return 178 * a valid object. 179 * @param xctxt The current execution context. 180 * @return A valid XObject. 181 * 182 * @throws javax.xml.transform.TransformerException 183 */ 184 public XObject execute(XPathContext xctxt) 185 throws javax.xml.transform.TransformerException 186 { 187 if (xctxt.isSecureProcessing()) 188 throw new javax.xml.transform.TransformerException( 189 XPATHMessages.createXPATHMessage( 190 XPATHErrorResources.ER_EXTENSION_FUNCTION_CANNOT_BE_INVOKED, 191 new Object[] {toString()})); 192 193 XObject result; 194 List<XObject> argVec = new ArrayList<>(); 195 int nArgs = m_argVec.size(); 196 197 for (int i = 0; i < nArgs; i++) 198 { 199 Expression arg = m_argVec.get(i); 200 201 XObject xobj = arg.execute(xctxt); 202 /* 203 * Should cache the arguments for func:function 204 */ 205 xobj.allowDetachToRelease(false); 206 argVec.add(xobj); 207 } 208 //dml 209 ExtensionsProvider extProvider = (ExtensionsProvider)xctxt.getOwnerObject(); 210 Object val = extProvider.extFunction(this, argVec); 211 212 if (null != val) 213 { 214 result = XObject.create(val, xctxt); 215 } 216 else 217 { 218 result = new XNull(); 219 } 220 221 return result; 222 } 223 224 /** 225 * Set an argument expression for a function. This method is called by the 226 * XPath compiler. 227 * 228 * @param arg non-null expression that represents the argument. 229 * @param argNum The argument number index. 230 * 231 * @throws WrongNumberArgsException If the argNum parameter is beyond what 232 * is specified for this function. 233 */ 234 public void setArg(Expression arg, int argNum) 235 throws WrongNumberArgsException 236 { 237 m_argVec.add(arg); 238 arg.exprSetParent(this); 239 } 240 241 /** 242 * Check that the number of arguments passed to this function is correct. 243 * 244 * 245 * @param argNum The number of arguments that is being passed to the function. 246 * 247 * @throws WrongNumberArgsException 248 */ 249 public void checkNumberArgs(int argNum) throws WrongNumberArgsException{} 250 251 252 class ArgExtOwner implements ExpressionOwner 253 { 254 255 Expression m_exp; 256 257 ArgExtOwner(Expression exp) 258 { 259 m_exp = exp; 260 } 261 262 /** 263 * @see ExpressionOwner#getExpression() 264 */ 265 public Expression getExpression() 266 { 267 return m_exp; 268 } 269 270 271 /** 272 * @see ExpressionOwner#setExpression(Expression) 273 */ 274 public void setExpression(Expression exp) 275 { 276 exp.exprSetParent(FuncExtFunction.this); 277 m_exp = exp; 278 } 279 } 280 281 282 /** 283 * Call the visitors for the function arguments. 284 */ 285 public void callArgVisitors(XPathVisitor visitor) 286 { 287 for (int i = 0; i < m_argVec.size(); i++) 288 { 289 Expression exp = m_argVec.get(i); 290 exp.callVisitors(new ArgExtOwner(exp), visitor); 291 } 292 293 } 294 295 /** 296 * Set the parent node. 297 * For an extension function, we also need to set the parent 298 * node for all argument expressions. 299 * 300 * @param n The parent node 301 */ 302 public void exprSetParent(ExpressionNode n) 303 { 304 305 super.exprSetParent(n); 306 307 int nArgs = m_argVec.size(); 308 309 for (int i = 0; i < nArgs; i++) 310 { 311 Expression arg = m_argVec.get(i); 312 313 arg.exprSetParent(n); 314 } 315 } 316 317 /** 318 * Constructs and throws a WrongNumberArgException with the appropriate 319 * message for this function object. This class supports an arbitrary 320 * number of arguments, so this method must never be called. 321 * 322 * @throws WrongNumberArgsException 323 */ 324 protected void reportWrongNumberArgs() throws WrongNumberArgsException { 325 String fMsg = XSLMessages.createXPATHMessage( 326 XPATHErrorResources.ER_INCORRECT_PROGRAMMER_ASSERTION, 327 new Object[]{ "Programmer's assertion: the method FunctionMultiArgs.reportWrongNumberArgs() should never be called." }); 328 329 throw new RuntimeException(fMsg); 330 } 331 332 /** 333 * Return the name of the extesion function in string format 334 */ 335 public String toString() 336 { 337 if (m_namespace != null && m_namespace.length() > 0) 338 return "{" + m_namespace + "}" + m_extensionName; 339 else 340 return m_extensionName; 341 } 342 }