1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the  "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 *     http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18/*
19 * $Id: ElemExtensionCall.java 468643 2006-10-28 06:56:03Z minchau $
20 */
21package org.apache.xalan.templates;
22
23import javax.xml.transform.TransformerException;
24
25import org.apache.xalan.extensions.ExtensionHandler;
26import org.apache.xalan.extensions.ExtensionsTable;
27import org.apache.xalan.res.XSLMessages;
28import org.apache.xalan.res.XSLTErrorResources;
29import org.apache.xalan.transformer.TransformerImpl;
30import org.apache.xpath.XPathContext;
31import org.xml.sax.SAXException;
32
33/**
34 * Implement an extension element.
35 * @see <a href="http://www.w3.org/TR/xslt#extension-element">extension-element in XSLT Specification</a>
36 * @xsl.usage advanced
37 */
38public class ElemExtensionCall extends ElemLiteralResult
39{
40    static final long serialVersionUID = 3171339708500216920L;
41
42  /** The Namespace URI for this extension call element.
43   *  @serial          */
44  String m_extns;
45
46  /** Language used by extension.
47   *  @serial          */
48  String m_lang;
49
50  /** URL pointing to extension.
51   *  @serial          */
52  String m_srcURL;
53
54  /** Source for script.
55   *  @serial          */
56  String m_scriptSrc;
57
58  /** Declaration for Extension element.
59   *  @serial          */
60  ElemExtensionDecl m_decl = null;
61
62  /**
63   * Get an int constant identifying the type of element.
64   * @see org.apache.xalan.templates.Constants
65   *
66   *@return The token ID for this element
67   */
68  public int getXSLToken()
69  {
70    return Constants.ELEMNAME_EXTENSIONCALL;
71  }
72
73  /**
74   * Return the node name.
75   *
76   * @return The element's name
77   */
78
79  // public String getNodeName()
80  // {
81  // TODO: Need prefix.
82  // return localPart;
83  // }
84
85  /**
86   * This function is called after everything else has been
87   * recomposed, and allows the template to set remaining
88   * values that may be based on some other property that
89   * depends on recomposition.
90   */
91  public void compose(StylesheetRoot sroot) throws TransformerException
92  {
93    super.compose(sroot);
94    m_extns = this.getNamespace();
95    m_decl = getElemExtensionDecl(sroot, m_extns);
96    // Register the extension namespace if the extension does not have
97    // an ElemExtensionDecl ("component").
98    if (m_decl == null)
99      sroot.getExtensionNamespacesManager().registerExtension(m_extns);
100  }
101
102  /**
103   * Return the ElemExtensionDecl for this extension element
104   *
105   *
106   * @param stylesheet Stylesheet root associated with this extension element
107   * @param namespace Namespace associated with this extension element
108   *
109   * @return the ElemExtensionDecl for this extension element.
110   */
111  private ElemExtensionDecl getElemExtensionDecl(StylesheetRoot stylesheet,
112          String namespace)
113  {
114
115    ElemExtensionDecl decl = null;
116    int n = stylesheet.getGlobalImportCount();
117
118    for (int i = 0; i < n; i++)
119    {
120      Stylesheet imported = stylesheet.getGlobalImport(i);
121
122      for (ElemTemplateElement child = imported.getFirstChildElem();
123              child != null; child = child.getNextSiblingElem())
124      {
125        if (Constants.ELEMNAME_EXTENSIONDECL == child.getXSLToken())
126        {
127          decl = (ElemExtensionDecl) child;
128
129          String prefix = decl.getPrefix();
130          String declNamespace = child.getNamespaceForPrefix(prefix);
131
132          if (namespace.equals(declNamespace))
133          {
134            return decl;
135          }
136        }
137      }
138    }
139
140    return null;
141  }
142
143  /**
144   * Execute the fallbacks when an extension is not available.
145   *
146   * @param transformer non-null reference to the the current transform-time state.
147   *
148   * @throws TransformerException
149   */
150  private void executeFallbacks(
151          TransformerImpl transformer)
152            throws TransformerException
153  {
154    for (ElemTemplateElement child = m_firstChild; child != null;
155             child = child.m_nextSibling)
156    {
157      if (child.getXSLToken() == Constants.ELEMNAME_FALLBACK)
158      {
159        try
160        {
161          transformer.pushElemTemplateElement(child);
162          ((ElemFallback) child).executeFallback(transformer);
163        }
164        finally
165        {
166          transformer.popElemTemplateElement();
167        }
168      }
169    }
170
171  }
172
173  /**
174   * Return true if this extension element has a <xsl:fallback> child element.
175   *
176   * @return true if this extension element has a <xsl:fallback> child element.
177   */
178  private boolean hasFallbackChildren()
179  {
180    for (ElemTemplateElement child = m_firstChild; child != null;
181             child = child.m_nextSibling)
182    {
183      if (child.getXSLToken() == Constants.ELEMNAME_FALLBACK)
184        return true;
185    }
186
187    return false;
188  }
189
190
191  /**
192   * Execute an extension.
193   *
194   * @param transformer non-null reference to the the current transform-time state.
195   *
196   * @throws TransformerException
197   */
198  public void execute(TransformerImpl transformer)
199            throws TransformerException
200  {
201    if (transformer.getStylesheet().isSecureProcessing())
202      throw new TransformerException(
203        XSLMessages.createMessage(
204          XSLTErrorResources.ER_EXTENSION_ELEMENT_NOT_ALLOWED_IN_SECURE_PROCESSING,
205          new Object[] {getRawName()}));
206
207    try
208    {
209      transformer.getResultTreeHandler().flushPending();
210
211      ExtensionsTable etable = transformer.getExtensionsTable();
212      ExtensionHandler nsh = etable.get(m_extns);
213
214      if (null == nsh)
215      {
216        if (hasFallbackChildren())
217        {
218          executeFallbacks(transformer);
219        }
220        else
221        {
222	  TransformerException te = new TransformerException(XSLMessages.createMessage(
223	  	XSLTErrorResources.ER_CALL_TO_EXT_FAILED, new Object[]{getNodeName()}));
224	  transformer.getErrorListener().fatalError(te);
225        }
226
227        return;
228      }
229
230      try
231      {
232        nsh.processElement(this.getLocalName(), this, transformer,
233                           getStylesheet(), this);
234      }
235      catch (Exception e)
236      {
237
238	if (hasFallbackChildren())
239	  executeFallbacks(transformer);
240	else
241	{
242          if(e instanceof TransformerException)
243          {
244            TransformerException te = (TransformerException)e;
245            if(null == te.getLocator())
246              te.setLocator(this);
247
248            transformer.getErrorListener().fatalError(te);
249          }
250          else if (e instanceof RuntimeException)
251          {
252            transformer.getErrorListener().fatalError(new TransformerException(e));
253          }
254          else
255          {
256            transformer.getErrorListener().warning(new TransformerException(e));
257          }
258        }
259      }
260    }
261    catch(TransformerException e)
262    {
263      transformer.getErrorListener().fatalError(e);
264    }
265    catch(SAXException se) {
266      throw new TransformerException(se);
267    }
268  }
269
270  /**
271   * Return the value of the attribute interpreted as an Attribute
272   * Value Template (in other words, you can use curly expressions
273   * such as href="http://{website}".
274   *
275   * @param rawName Raw name of the attribute to get
276   * @param sourceNode non-null reference to the <a href="http://www.w3.org/TR/xslt#dt-current-node">current source node</a>.
277   * @param transformer non-null reference to the the current transform-time state.
278   *
279   * @return the value of the attribute
280   *
281   * @throws TransformerException
282   */
283  public String getAttribute(
284          String rawName, org.w3c.dom.Node sourceNode, TransformerImpl transformer)
285            throws TransformerException
286  {
287
288    AVT avt = getLiteralResultAttribute(rawName);
289
290    if ((null != avt) && avt.getRawName().equals(rawName))
291    {
292      XPathContext xctxt = transformer.getXPathContext();
293
294      return avt.evaluate(xctxt,
295            xctxt.getDTMHandleFromNode(sourceNode),
296            this);
297    }
298
299    return null;
300  }
301
302  /**
303   * Accept a visitor and call the appropriate method
304   * for this class.
305   *
306   * @param visitor The visitor whose appropriate method will be called.
307   * @return true if the children of the object should be visited.
308   */
309  protected boolean accept(XSLTVisitor visitor)
310  {
311  	return visitor.visitExtensionElement(this);
312  }
313
314
315}
316