001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 /* 019 * $Id: FuncExtFunction.java 468655 2006-10-28 07:12:06Z minchau $ 020 */ 021 package org.apache.xpath.functions; 022 023 import java.util.Vector; 024 025 import org.apache.xalan.res.XSLMessages; 026 import org.apache.xpath.Expression; 027 import org.apache.xpath.ExpressionNode; 028 import org.apache.xpath.ExpressionOwner; 029 import org.apache.xpath.ExtensionsProvider; 030 import org.apache.xpath.XPathContext; 031 import org.apache.xpath.XPathVisitor; 032 import org.apache.xpath.objects.XNull; 033 import org.apache.xpath.objects.XObject; 034 import org.apache.xpath.res.XPATHErrorResources; 035 import org.apache.xpath.res.XPATHMessages; 036 037 /** 038 * An object of this class represents an extension call expression. When 039 * the expression executes, it calls ExtensionsTable#extFunction, and then 040 * converts the result to the appropriate XObject. 041 * @xsl.usage advanced 042 */ 043 public class FuncExtFunction extends Function 044 { 045 static final long serialVersionUID = 5196115554693708718L; 046 047 /** 048 * The namespace for the extension function, which should not normally 049 * be null or empty. 050 * @serial 051 */ 052 String m_namespace; 053 054 /** 055 * The local name of the extension. 056 * @serial 057 */ 058 String m_extensionName; 059 060 /** 061 * Unique method key, which is passed to ExtensionsTable#extFunction in 062 * order to allow caching of the method. 063 * @serial 064 */ 065 Object m_methodKey; 066 067 /** 068 * Array of static expressions which represent the parameters to the 069 * function. 070 * @serial 071 */ 072 Vector m_argVec = new Vector(); 073 074 /** 075 * This function is used to fixup variables from QNames to stack frame 076 * indexes at stylesheet build time. 077 * @param vars List of QNames that correspond to variables. This list 078 * should be searched backwards for the first qualified name that 079 * corresponds to the variable reference qname. The position of the 080 * QName in the vector from the start of the vector will be its position 081 * in the stack frame (but variables above the globalsTop value will need 082 * to be offset to the current stack frame). 083 * NEEDSDOC @param globalsSize 084 */ 085 public void fixupVariables(java.util.Vector vars, int globalsSize) 086 { 087 088 if (null != m_argVec) 089 { 090 int nArgs = m_argVec.size(); 091 092 for (int i = 0; i < nArgs; i++) 093 { 094 Expression arg = (Expression) m_argVec.elementAt(i); 095 096 arg.fixupVariables(vars, globalsSize); 097 } 098 } 099 } 100 101 /** 102 * Return the namespace of the extension function. 103 * 104 * @return The namespace of the extension function. 105 */ 106 public String getNamespace() 107 { 108 return m_namespace; 109 } 110 111 /** 112 * Return the name of the extension function. 113 * 114 * @return The name of the extension function. 115 */ 116 public String getFunctionName() 117 { 118 return m_extensionName; 119 } 120 121 /** 122 * Return the method key of the extension function. 123 * 124 * @return The method key of the extension function. 125 */ 126 public Object getMethodKey() 127 { 128 return m_methodKey; 129 } 130 131 /** 132 * Return the nth argument passed to the extension function. 133 * 134 * @param n The argument number index. 135 * @return The Expression object at the given index. 136 */ 137 public Expression getArg(int n) { 138 if (n >= 0 && n < m_argVec.size()) 139 return (Expression) m_argVec.elementAt(n); 140 else 141 return null; 142 } 143 144 /** 145 * Return the number of arguments that were passed 146 * into this extension function. 147 * 148 * @return The number of arguments. 149 */ 150 public int getArgCount() { 151 return m_argVec.size(); 152 } 153 154 /** 155 * Create a new FuncExtFunction based on the qualified name of the extension, 156 * and a unique method key. 157 * 158 * @param namespace The namespace for the extension function, which should 159 * not normally be null or empty. 160 * @param extensionName The local name of the extension. 161 * @param methodKey Unique method key, which is passed to 162 * ExtensionsTable#extFunction in order to allow caching 163 * of the method. 164 */ 165 public FuncExtFunction(java.lang.String namespace, 166 java.lang.String extensionName, Object methodKey) 167 { 168 //try{throw new Exception("FuncExtFunction() " + namespace + " " + extensionName);} catch (Exception e){e.printStackTrace();} 169 m_namespace = namespace; 170 m_extensionName = extensionName; 171 m_methodKey = methodKey; 172 } 173 174 /** 175 * Execute the function. The function must return 176 * a valid object. 177 * @param xctxt The current execution context. 178 * @return A valid XObject. 179 * 180 * @throws javax.xml.transform.TransformerException 181 */ 182 public XObject execute(XPathContext xctxt) 183 throws javax.xml.transform.TransformerException 184 { 185 if (xctxt.isSecureProcessing()) 186 throw new javax.xml.transform.TransformerException( 187 XPATHMessages.createXPATHMessage( 188 XPATHErrorResources.ER_EXTENSION_FUNCTION_CANNOT_BE_INVOKED, 189 new Object[] {toString()})); 190 191 XObject result; 192 Vector argVec = new Vector(); 193 int nArgs = m_argVec.size(); 194 195 for (int i = 0; i < nArgs; i++) 196 { 197 Expression arg = (Expression) m_argVec.elementAt(i); 198 199 XObject xobj = arg.execute(xctxt); 200 /* 201 * Should cache the arguments for func:function 202 */ 203 xobj.allowDetachToRelease(false); 204 argVec.addElement(xobj); 205 } 206 //dml 207 ExtensionsProvider extProvider = (ExtensionsProvider)xctxt.getOwnerObject(); 208 Object val = extProvider.extFunction(this, argVec); 209 210 if (null != val) 211 { 212 result = XObject.create(val, xctxt); 213 } 214 else 215 { 216 result = new XNull(); 217 } 218 219 return result; 220 } 221 222 /** 223 * Set an argument expression for a function. This method is called by the 224 * XPath compiler. 225 * 226 * @param arg non-null expression that represents the argument. 227 * @param argNum The argument number index. 228 * 229 * @throws WrongNumberArgsException If the argNum parameter is beyond what 230 * is specified for this function. 231 */ 232 public void setArg(Expression arg, int argNum) 233 throws WrongNumberArgsException 234 { 235 m_argVec.addElement(arg); 236 arg.exprSetParent(this); 237 } 238 239 /** 240 * Check that the number of arguments passed to this function is correct. 241 * 242 * 243 * @param argNum The number of arguments that is being passed to the function. 244 * 245 * @throws WrongNumberArgsException 246 */ 247 public void checkNumberArgs(int argNum) throws WrongNumberArgsException{} 248 249 250 class ArgExtOwner implements ExpressionOwner 251 { 252 253 Expression m_exp; 254 255 ArgExtOwner(Expression exp) 256 { 257 m_exp = exp; 258 } 259 260 /** 261 * @see ExpressionOwner#getExpression() 262 */ 263 public Expression getExpression() 264 { 265 return m_exp; 266 } 267 268 269 /** 270 * @see ExpressionOwner#setExpression(Expression) 271 */ 272 public void setExpression(Expression exp) 273 { 274 exp.exprSetParent(FuncExtFunction.this); 275 m_exp = exp; 276 } 277 } 278 279 280 /** 281 * Call the visitors for the function arguments. 282 */ 283 public void callArgVisitors(XPathVisitor visitor) 284 { 285 for (int i = 0; i < m_argVec.size(); i++) 286 { 287 Expression exp = (Expression)m_argVec.elementAt(i); 288 exp.callVisitors(new ArgExtOwner(exp), visitor); 289 } 290 291 } 292 293 /** 294 * Set the parent node. 295 * For an extension function, we also need to set the parent 296 * node for all argument expressions. 297 * 298 * @param n The parent node 299 */ 300 public void exprSetParent(ExpressionNode n) 301 { 302 303 super.exprSetParent(n); 304 305 int nArgs = m_argVec.size(); 306 307 for (int i = 0; i < nArgs; i++) 308 { 309 Expression arg = (Expression) m_argVec.elementAt(i); 310 311 arg.exprSetParent(n); 312 } 313 } 314 315 /** 316 * Constructs and throws a WrongNumberArgException with the appropriate 317 * message for this function object. This class supports an arbitrary 318 * number of arguments, so this method must never be called. 319 * 320 * @throws WrongNumberArgsException 321 */ 322 protected void reportWrongNumberArgs() throws WrongNumberArgsException { 323 String fMsg = XSLMessages.createXPATHMessage( 324 XPATHErrorResources.ER_INCORRECT_PROGRAMMER_ASSERTION, 325 new Object[]{ "Programmer's assertion: the method FunctionMultiArgs.reportWrongNumberArgs() should never be called." }); 326 327 throw new RuntimeException(fMsg); 328 } 329 330 /** 331 * Return the name of the extesion function in string format 332 */ 333 public String toString() 334 { 335 if (m_namespace != null && m_namespace.length() > 0) 336 return "{" + m_namespace + "}" + m_extensionName; 337 else 338 return m_extensionName; 339 } 340 }