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