001: package net.sf.saxon.functions;
002:
003: import net.sf.saxon.expr.Expression;
004: import net.sf.saxon.expr.StaticContext;
005: import net.sf.saxon.expr.XPathContext;
006: import net.sf.saxon.om.*;
007: import net.sf.saxon.style.StyleNodeFactory;
008: import net.sf.saxon.style.XSLTStaticContext;
009: import net.sf.saxon.trans.StaticError;
010: import net.sf.saxon.trans.XPathException;
011: import net.sf.saxon.value.*;
012: import net.sf.saxon.Configuration;
013:
014: /**
015: * This class supports the XSLT element-available and function-available functions.
016: */
017:
018: public class Available extends SystemFunction implements XSLTFunction {
019:
020: public static final int ELEMENT_AVAILABLE = 0;
021: public static final int FUNCTION_AVAILABLE = 1;
022:
023: private transient NamespaceResolver nsContext;
024: private transient StyleNodeFactory styleNodeFactory;
025: private transient boolean checked = false;
026:
027: // the second time checkArguments is called, it's a global check so the static context is inaccurate
028:
029: public void checkArguments(StaticContext env) throws XPathException {
030: if (checked)
031: return;
032: checked = true;
033: super .checkArguments(env);
034: if (!(argument[0] instanceof Value && (argument.length == 1 || argument[1] instanceof Value))) {
035: // we need to save the namespace context
036: nsContext = env.getNamespaceResolver();
037: }
038: }
039:
040: /**
041: * preEvaluate: this method uses the static context to do early evaluation of the function
042: * if the argument is known (which is the normal case)
043: */
044:
045: public Expression preEvaluate(StaticContext env)
046: throws XPathException {
047: String qname = ((StringValue) argument[0]).getStringValue();
048:
049: boolean b = false;
050: switch (operation) {
051: case ELEMENT_AVAILABLE:
052: b = ((XSLTStaticContext) env).isElementAvailable(qname);
053: break;
054: case FUNCTION_AVAILABLE:
055: long arity = -1;
056: if (argument.length == 2) {
057: arity = ((NumericValue) argument[1].evaluateItem(env
058: .makeEarlyEvaluationContext())).longValue();
059: }
060: try {
061: String[] parts = env.getConfiguration()
062: .getNameChecker().getQNameParts(qname);
063: String prefix = parts[0];
064: String uri;
065: if (prefix.equals("")) {
066: uri = env.getDefaultFunctionNamespace();
067: } else {
068: uri = env.getURIForPrefix(prefix);
069: }
070: int fingerprint = env.getNamePool().allocate(prefix,
071: uri, parts[1]) & 0xfffff;
072: b = env.getFunctionLibrary().isAvailable(fingerprint,
073: uri, parts[1], (int) arity);
074: } catch (QNameException e) {
075: throw new StaticError(e.getMessage());
076: }
077: break;
078: }
079: return BooleanValue.get(b);
080: }
081:
082: /**
083: * Run-time evaluation. This is the only thing in the spec that requires information
084: * about in-scope functions to be available at run-time. However, we keep it because
085: * it's handy for some other things such as saxon:evaluate().
086: */
087:
088: public Item evaluateItem(XPathContext context)
089: throws XPathException {
090: AtomicValue av1 = (AtomicValue) argument[0]
091: .evaluateItem(context);
092: long arity = -1;
093: if (argument.length == 2) {
094: arity = ((NumericValue) argument[1].evaluateItem(context))
095: .longValue();
096: }
097: StringValue nameValue = (StringValue) av1.getPrimitiveValue();
098: String name = nameValue.getStringValue();
099: String[] parts = null;
100: try {
101: parts = context.getConfiguration().getNameChecker()
102: .getQNameParts(name);
103: } catch (QNameException e) {
104: String code = (operation == FUNCTION_AVAILABLE ? "XTDE1400"
105: : "XTDE1440");
106: dynamicError(e.getMessage(), code, context);
107: }
108: String prefix = parts[0];
109: String lname = parts[1];
110: String uri;
111: if (prefix.equals("")) {
112: if (operation == ELEMENT_AVAILABLE) {
113: // Use the default namespace for ELEMENT_AVAILABLE only
114: uri = nsContext.getURIForPrefix(prefix, true);
115: } else {
116: uri = NamespaceConstant.FN;
117: }
118: } else {
119: uri = nsContext.getURIForPrefix(prefix, false);
120: }
121: if (uri == null) {
122: dynamicError("Namespace prefix '" + prefix
123: + "' has not been declared", context);
124: }
125:
126: boolean b = false;
127: switch (operation) {
128: case ELEMENT_AVAILABLE:
129: b = isElementAvailable(uri, lname, context);
130: break;
131: case FUNCTION_AVAILABLE:
132: final int fingerprint = context.getNamePool().allocate(
133: prefix, uri, lname) & 0xfffff;
134: final FunctionLibrary lib = context.getController()
135: .getExecutable().getFunctionLibrary();
136: b = lib.isAvailable(fingerprint, uri, lname, (int) arity);
137: break;
138: }
139: return BooleanValue.get(b);
140:
141: }
142:
143: /**
144: * Determine at run-time whether a particular instruction is available. Returns true
145: * only in the case of XSLT instructions and Saxon extension instructions; returns false
146: * for user-defined extension instructions
147: */
148:
149: private boolean isElementAvailable(String uri, String localname,
150: XPathContext context) {
151:
152: // This is horribly inefficient. But hopefully it's hardly ever executed, because there
153: // is very little point calling element-available() with a dynamically-constructed argument.
154: // And the inefficiency is only incurred once, on the first call.
155:
156: // Note: this requires the compile-time classes to be available at run-time; it will need
157: // changing if we ever want to build a run-time JAR file.
158:
159: try {
160: if (styleNodeFactory == null) {
161: Configuration config = context.getConfiguration();
162: styleNodeFactory = new StyleNodeFactory(config);
163: }
164: return styleNodeFactory.isElementAvailable(uri, localname);
165: } catch (Exception err) {
166: //err.printStackTrace();
167: return false;
168: }
169: }
170:
171: }
172:
173: //
174: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
175: // you may not use this file except in compliance with the License. You may obtain a copy of the
176: // License at http://www.mozilla.org/MPL/
177: //
178: // Software distributed under the License is distributed on an "AS IS" basis,
179: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
180: // See the License for the specific language governing rights and limitations under the License.
181: //
182: // The Original Code is: all this file.
183: //
184: // The Initial Developer of the Original Code is Michael H. Kay.
185: //
186: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
187: //
188: // Contributor(s): none.
189: //
|