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: TrAXFilter.java 468645 2006-10-28 06:57:24Z minchau $
020     */
021    package org.apache.xalan.transformer;
022    
023    import java.io.IOException;
024    
025    import javax.xml.XMLConstants;
026    import javax.xml.transform.ErrorListener;
027    import javax.xml.transform.Templates;
028    import javax.xml.transform.TransformerConfigurationException;
029    
030    import org.apache.xalan.res.XSLMessages;
031    import org.apache.xalan.res.XSLTErrorResources;
032    
033    import org.xml.sax.ContentHandler;
034    import org.xml.sax.DTDHandler;
035    import org.xml.sax.EntityResolver;
036    import org.xml.sax.InputSource;
037    import org.xml.sax.XMLReader;
038    import org.xml.sax.helpers.XMLFilterImpl;
039    import org.xml.sax.helpers.XMLReaderFactory;
040    
041    
042    public class TrAXFilter extends XMLFilterImpl
043    {
044      private Templates m_templates;
045      private TransformerImpl m_transformer;
046        
047      /**
048       * Construct an empty XML filter, with no parent.
049       *
050       * <p>This filter will have no parent: you must assign a parent
051       * before you start a parse or do any configuration with
052       * setFeature or setProperty.</p>
053       *
054       * @see org.xml.sax.XMLReader#setFeature
055       * @see org.xml.sax.XMLReader#setProperty
056       */
057      public TrAXFilter (Templates templates)
058        throws TransformerConfigurationException
059      {
060        m_templates = templates;
061        m_transformer = (TransformerImpl)templates.newTransformer();
062      }
063      
064      /**
065       * Return the Transformer object used for this XML filter.
066       */
067      public TransformerImpl getTransformer()
068      {
069        return m_transformer;
070      }
071      
072      /** Set the parent reader.
073       *
074       * <p>This is the {@link org.xml.sax.XMLReader XMLReader} from which 
075       * this filter will obtain its events and to which it will pass its 
076       * configuration requests.  The parent may itself be another filter.</p>
077       *
078       * <p>If there is no parent reader set, any attempt to parse
079       * or to set or get a feature or property will fail.</p>
080       *
081       * @param parent The parent XML reader.
082       * @throws java.lang.NullPointerException If the parent is null.
083       */
084      public void setParent (XMLReader parent)
085      { 
086        super.setParent(parent);
087        
088        if(null != parent.getContentHandler())
089          this.setContentHandler(parent.getContentHandler());
090    
091        // Not really sure if we should do this here, but 
092        // it seems safer in case someone calls parse() on 
093        // the parent.
094        setupParse ();
095      }
096      
097      /**
098       * Parse a document.
099       *
100       * @param input The input source for the document entity.
101       * @throws org.xml.sax.SAXException Any SAX exception, possibly
102       *            wrapping another exception.
103       * @throws java.io.IOException An IO exception from the parser,
104       *            possibly from a byte stream or character stream
105       *            supplied by the application.
106       * @see org.xml.sax.XMLReader#parse(org.xml.sax.InputSource)
107       */
108      public void parse (InputSource input)
109        throws org.xml.sax.SAXException, IOException
110      {
111        if(null == getParent())
112        {
113          XMLReader reader=null;
114    
115          // Use JAXP1.1 ( if possible )
116          try {
117              javax.xml.parsers.SAXParserFactory factory=
118                  javax.xml.parsers.SAXParserFactory.newInstance();
119              factory.setNamespaceAware( true );
120              
121              if (m_transformer.getStylesheet().isSecureProcessing()) {
122                  try {
123                      factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
124                  }
125                  catch (org.xml.sax.SAXException se) {}
126              }
127              
128              javax.xml.parsers.SAXParser jaxpParser=
129                  factory.newSAXParser();
130              reader=jaxpParser.getXMLReader();
131              
132          } catch( javax.xml.parsers.ParserConfigurationException ex ) {
133              throw new org.xml.sax.SAXException( ex );
134          } catch( javax.xml.parsers.FactoryConfigurationError ex1 ) {
135              throw new org.xml.sax.SAXException( ex1.toString() );
136          } catch( NoSuchMethodError ex2 ) {
137          }
138          catch (AbstractMethodError ame){}
139    
140          XMLReader parent;
141          if( reader==null )
142              parent= XMLReaderFactory.createXMLReader();
143          else
144              parent=reader;
145          try
146          {
147            parent.setFeature("http://xml.org/sax/features/namespace-prefixes",
148                              true);
149          }
150          catch (org.xml.sax.SAXException se){}
151          // setParent calls setupParse...
152          setParent(parent);
153        }
154        else
155        {
156          // Make sure everything is set up.
157          setupParse ();
158        }
159        if(null == m_transformer.getContentHandler())
160        {
161          throw new org.xml.sax.SAXException(XSLMessages.createMessage(XSLTErrorResources.ER_CANNOT_CALL_PARSE, null)); //"parse can not be called if the ContentHandler has not been set!");
162        }
163    
164        getParent().parse(input);
165        Exception e = m_transformer.getExceptionThrown();
166        if(null != e)
167        {
168          if(e instanceof org.xml.sax.SAXException)
169            throw (org.xml.sax.SAXException)e;
170          else
171            throw new org.xml.sax.SAXException(e);
172        }
173      }
174      
175      /**
176       * Parse a document.
177       *
178       * @param systemId The system identifier as a fully-qualified URI.
179       * @throws org.xml.sax.SAXException Any SAX exception, possibly
180       *            wrapping another exception.
181       * @throws java.io.IOException An IO exception from the parser,
182       *            possibly from a byte stream or character stream
183       *            supplied by the application.
184       * @see org.xml.sax.XMLReader#parse(java.lang.String)
185       */
186      public void parse (String systemId)
187        throws org.xml.sax.SAXException, IOException
188      {
189        parse(new InputSource(systemId));
190      }
191    
192    
193      /**
194       * Set up before a parse.
195       *
196       * <p>Before every parse, check whether the parent is
197       * non-null, and re-register the filter for all of the 
198       * events.</p>
199       */
200      private void setupParse ()
201      {
202        XMLReader p = getParent();
203        if (p == null) {
204          throw new NullPointerException(XSLMessages.createMessage(XSLTErrorResources.ER_NO_PARENT_FOR_FILTER, null)); //"No parent for filter");
205        }
206        
207        ContentHandler ch = m_transformer.getInputContentHandler();
208    //    if(ch instanceof SourceTreeHandler)
209    //      ((SourceTreeHandler)ch).setUseMultiThreading(true);
210        p.setContentHandler(ch);
211        p.setEntityResolver(this);
212        p.setDTDHandler(this);
213        p.setErrorHandler(this);
214      }
215    
216      /**
217       * Set the content event handler.
218       *
219       * @param handler The new content handler.
220       * @throws java.lang.NullPointerException If the handler
221       *            is null.
222       * @see org.xml.sax.XMLReader#setContentHandler
223       */
224      public void setContentHandler (ContentHandler handler)
225      {
226        m_transformer.setContentHandler(handler);
227        // super.setContentHandler(m_transformer.getResultTreeHandler());
228      }
229      
230      public void setErrorListener (ErrorListener handler)
231      {
232        m_transformer.setErrorListener(handler);
233      }
234    
235    }