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  */
21 package org.apache.xalan.templates;
22 
23 import javax.xml.transform.TransformerException;
24 
25 import org.apache.xalan.extensions.ExtensionHandler;
26 import org.apache.xalan.extensions.ExtensionsTable;
27 import org.apache.xalan.res.XSLMessages;
28 import org.apache.xalan.res.XSLTErrorResources;
29 import org.apache.xalan.transformer.TransformerImpl;
30 import org.apache.xpath.XPathContext;
31 import 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  */
38 public 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    */
getXSLToken()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    */
compose(StylesheetRoot sroot)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    */
getElemExtensionDecl(StylesheetRoot stylesheet, String namespace)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    */
executeFallbacks( TransformerImpl transformer)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    */
hasFallbackChildren()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    */
execute(TransformerImpl transformer)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    */
getAttribute( String rawName, org.w3c.dom.Node sourceNode, TransformerImpl transformer)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    */
accept(XSLTVisitor visitor)309   protected boolean accept(XSLTVisitor visitor)
310   {
311   	return visitor.visitExtensionElement(this);
312   }
313 
314 
315 }
316