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: ElemExtensionCall.java 468643 2006-10-28 06:56:03Z minchau $
020     */
021    package org.apache.xalan.templates;
022    
023    import javax.xml.transform.TransformerException;
024    
025    import org.apache.xalan.extensions.ExtensionHandler;
026    import org.apache.xalan.extensions.ExtensionsTable;
027    import org.apache.xalan.res.XSLMessages;
028    import org.apache.xalan.res.XSLTErrorResources;
029    import org.apache.xalan.transformer.TransformerImpl;
030    import org.apache.xpath.XPathContext;
031    import org.xml.sax.SAXException;
032    
033    /**
034     * Implement an extension element.
035     * @see <a href="http://www.w3.org/TR/xslt#extension-element">extension-element in XSLT Specification</a>
036     * @xsl.usage advanced
037     */
038    public class ElemExtensionCall extends ElemLiteralResult
039    {
040        static final long serialVersionUID = 3171339708500216920L;
041    
042      /** The Namespace URI for this extension call element.
043       *  @serial          */
044      String m_extns;
045    
046      /** Language used by extension.
047       *  @serial          */
048      String m_lang;
049    
050      /** URL pointing to extension.
051       *  @serial          */
052      String m_srcURL;
053    
054      /** Source for script.
055       *  @serial          */
056      String m_scriptSrc;
057    
058      /** Declaration for Extension element. 
059       *  @serial          */
060      ElemExtensionDecl m_decl = null;
061    
062      /**
063       * Get an int constant identifying the type of element.
064       * @see org.apache.xalan.templates.Constants
065       *
066       *@return The token ID for this element
067       */
068      public int getXSLToken()
069      {
070        return Constants.ELEMNAME_EXTENSIONCALL;
071      }
072    
073      /**
074       * Return the node name.
075       *
076       * @return The element's name
077       */
078    
079      // public String getNodeName()
080      // {
081      // TODO: Need prefix.
082      // return localPart;
083      // }
084    
085      /**
086       * This function is called after everything else has been
087       * recomposed, and allows the template to set remaining
088       * values that may be based on some other property that
089       * depends on recomposition.
090       */
091      public void compose(StylesheetRoot sroot) throws TransformerException
092      {
093        super.compose(sroot);
094        m_extns = this.getNamespace();   
095        m_decl = getElemExtensionDecl(sroot, m_extns);
096        // Register the extension namespace if the extension does not have
097        // an ElemExtensionDecl ("component").
098        if (m_decl == null)
099          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        if (transformer.getDebug())
208                    transformer.getTraceManager().fireTraceEvent(this);
209        try
210        {
211          transformer.getResultTreeHandler().flushPending();
212    
213          ExtensionsTable etable = transformer.getExtensionsTable();
214          ExtensionHandler nsh = etable.get(m_extns);
215    
216          if (null == nsh)
217          {
218            if (hasFallbackChildren())
219            {
220              executeFallbacks(transformer);
221            }
222            else
223            {
224              TransformerException te = new TransformerException(XSLMessages.createMessage(
225                    XSLTErrorResources.ER_CALL_TO_EXT_FAILED, new Object[]{getNodeName()}));
226              transformer.getErrorListener().fatalError(te);
227            }
228            
229            return;
230          }
231    
232          try
233          {
234            nsh.processElement(this.getLocalName(), this, transformer,
235                               getStylesheet(), this);
236          }
237          catch (Exception e)
238          {
239    
240            if (hasFallbackChildren())
241              executeFallbacks(transformer);
242            else
243            {
244              if(e instanceof TransformerException)
245              {
246                TransformerException te = (TransformerException)e;
247                if(null == te.getLocator())
248                  te.setLocator(this);
249                
250                transformer.getErrorListener().fatalError(te);            
251              }
252              else if (e instanceof RuntimeException)
253              {
254                transformer.getErrorListener().fatalError(new TransformerException(e));
255              }
256              else
257              {
258                transformer.getErrorListener().warning(new TransformerException(e));
259              }
260            }
261          }
262        }
263        catch(TransformerException e)
264        {
265          transformer.getErrorListener().fatalError(e);
266        }
267        catch(SAXException se) {
268          throw new TransformerException(se);
269        }
270        if (transformer.getDebug())
271                    transformer.getTraceManager().fireTraceEndEvent(this);
272      }
273    
274      /**
275       * Return the value of the attribute interpreted as an Attribute
276       * Value Template (in other words, you can use curly expressions
277       * such as href="http://{website}".
278       *
279       * @param rawName Raw name of the attribute to get
280       * @param sourceNode non-null reference to the <a href="http://www.w3.org/TR/xslt#dt-current-node">current source node</a>.
281       * @param transformer non-null reference to the the current transform-time state.
282       *
283       * @return the value of the attribute
284       *
285       * @throws TransformerException
286       */
287      public String getAttribute(
288              String rawName, org.w3c.dom.Node sourceNode, TransformerImpl transformer)
289                throws TransformerException
290      {
291    
292        AVT avt = getLiteralResultAttribute(rawName);
293    
294        if ((null != avt) && avt.getRawName().equals(rawName))
295        {
296          XPathContext xctxt = transformer.getXPathContext();
297    
298          return avt.evaluate(xctxt, 
299                xctxt.getDTMHandleFromNode(sourceNode), 
300                this);
301        }
302    
303        return null;
304      }
305      
306      /**
307       * Accept a visitor and call the appropriate method 
308       * for this class.
309       * 
310       * @param visitor The visitor whose appropriate method will be called.
311       * @return true if the children of the object should be visited.
312       */
313      protected boolean accept(XSLTVisitor visitor)
314      {
315            return visitor.visitExtensionElement(this);
316      }
317    
318      
319    }